myna-card 3.3.0

A library for accessing the Japanese Individual Number Card (個人番号カード) over PC/SC
Documentation
//! 住基AP — the resident registry network application.
//!
//! The least understood of the five. It exposes one record structured EF whose content has not
//! been identified, and a key reference whose verification does not visibly change the security
//! status of anything else in the application.
//!
//! No secure messaging reachable from here. SET SESSION KEY answers `6982` even with the PIN
//! presented, and this application publishes no key to deliver a session key under. Unlike the
//! `66F1` of the 共通カード and 券面事項確認 applications, `6982` says the card *has* something
//! configured and the credential is not it. See [`crate::sm`].

use crate::card::{Card, Retries};
use crate::error::Result;
use crate::pin::Pin;
use crate::transport::Transmit;

/// AID of the resident registry network application.
pub const DF: [u8; 10] = [0xD3, 0x92, 0x10, 0x00, 0x31, 0x00, 0x01, 0x01, 0x04, 0x01];

/// File identifiers within the resident registry network application.
pub mod ef {
    /// One 16 byte key reference, byte-identical to EF `0002` of the 共通カード application.
    pub const KEY_REFERENCE: u16 = 0x0002;
    /// Key reference for the four digit PIN in the 住基 application.
    ///
    /// User interfaces group it with 共通カードAP `001C` as one 個人番号カード用 PIN, but they
    /// are separate key references and must be changed separately.
    pub const PIN: u16 = 0x001C;
}

/// The resident registry network application, selected on a card.
#[derive(Debug)]
pub struct JukiAp<'a, T> {
    card: &'a mut Card<T>,
}

impl<'a, T: Transmit> JukiAp<'a, T> {
    /// Select the application.
    pub fn select(card: &'a mut Card<T>) -> Result<Self> {
        card.select_df(&DF)?;
        Ok(JukiAp { card })
    }

    /// Borrow the underlying card, for operations this wrapper does not cover.
    pub fn card(&mut self) -> &mut Card<T> {
        self.card
    }

    /// Read one record of a record structured EF of this application. Records start at 1.
    pub fn read_record(&mut self, id: u16, record: u8) -> Result<Vec<u8>> {
        self.card.select_ef(id)?;
        self.card.read_record(record)
    }

    /// Present the PIN.
    pub fn verify_pin(&mut self, pin: &Pin) -> Result<()> {
        self.card.select_ef(ef::PIN)?;
        self.card.verify(pin)
    }

    /// Change the four digit PIN in the 住基 application.
    ///
    /// What user interfaces call the 個人番号カード用 PIN has one key reference here and
    /// another in the 本人確認業務用領域. Changing both therefore requires calling this method
    /// and [`CommonAp::change_pin`](crate::ap::common::CommonAp::change_pin); either operation may
    /// succeed independently. This method first presents `current_pin`, consuming a retry on
    /// failure, then replaces it with `new_pin` using JICSAP CHANGE KEY.
    pub fn change_pin(&mut self, current_pin: &Pin, new_pin: &Pin) -> Result<()> {
        self.card.select_ef(ef::PIN)?;
        self.card.verify(current_pin)?;
        self.card.change_key(new_pin)
    }

    /// Attempts remaining on the PIN, without spending one.
    pub fn pin_retries(&mut self) -> Result<Retries> {
        self.card.select_ef(ef::PIN)?;
        self.card.pin_retries()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::transport::mock::MockTransport;

    #[test]
    fn changing_the_pin_uses_jicsap_change_key() {
        let mut card = Card::new(MockTransport::new([
            vec![0x90, 0x00], // SELECT DF
            vec![0x90, 0x00], // SELECT EF 001C
            vec![0x90, 0x00], // VERIFY current PIN
            vec![0x90, 0x00], // CHANGE KEY
        ]));
        let mut juki = JukiAp::select(&mut card).unwrap();
        juki.change_pin(
            &Pin::numeric("1234").unwrap(),
            &Pin::numeric("5678").unwrap(),
        )
        .unwrap();

        assert_eq!(
            card.transport().sent[1],
            [0x00, 0xA4, 0x02, 0x0C, 0x02, 0x00, 0x1C]
        );
        assert_eq!(
            card.transport().sent[3],
            [0x80, 0x32, 0x00, 0x80, 0x04, b'5', b'6', b'7', b'8']
        );
    }
}