use std::rc::Rc;
use crate::ap::open;
use crate::{card, nfc, Card};
const DF_NAME: [u8; 10] = [0xD3, 0x92, 0xF0, 0x00, 0x26, 0x01, 0x00, 0x00, 0x00, 0x01];
const EF_AUTH: [u8; 2] = [0x00, 0x17];
const EF_AUTH_PIN: [u8; 2] = [0x00, 0x18];
const EF_SIGN: [u8; 2] = [0x00, 0x1A];
const EF_SIGN_PIN: [u8; 2] = [0x00, 0x1B];
#[derive(Copy, Clone)]
pub enum CertType {
Auth,
AuthCA,
Sign,
SignCA,
}
impl CertType {
pub fn into_efid(self) -> [u8; 2] {
match self {
Self::Auth => [0x00, 0x0A],
Self::AuthCA => [0x00, 0x0B],
Self::Sign => [0x00, 0x01],
Self::SignCA => [0x00, 0x02],
}
}
pub fn is_pin_required(&self) -> bool {
matches!(self, Self::Sign)
}
}
pub struct CryptoAp<T, Ctx>
where
T: nfc::HandlerInCtx<Ctx>,
Ctx: Copy,
{
card: Rc<Card<T, Ctx>>,
}
impl<T, Ctx> CryptoAp<T, Ctx>
where
T: nfc::HandlerInCtx<Ctx>,
Ctx: Copy,
{
open!(T, Ctx, DF_NAME);
pub fn read_certificate(
&self,
ctx: Ctx,
ty: CertType,
pin: Vec<u8>,
) -> Result<Vec<u8>, card::Error> {
if ty.is_pin_required() {
self.verify_sign_pin(ctx, pin)?;
}
self.card
.select_ef(ctx, ty.into_efid().into())
.and_then(|_| self.card.read_der_size(ctx))
.and_then(|size| self.card.read(ctx, Some(size)))
}
pub fn auth(&self, ctx: Ctx, pin: Vec<u8>, digest: Vec<u8>) -> Result<Vec<u8>, card::Error> {
self.verify_auth_pin(ctx, pin)
.and_then(|_| self.card.select_ef(ctx, EF_AUTH.into()))
.and_then(|_| self.card.sign(ctx, digest))
}
pub fn sign(&self, ctx: Ctx, pin: Vec<u8>, digest: Vec<u8>) -> Result<Vec<u8>, card::Error> {
self.verify_sign_pin(ctx, pin)
.and_then(|_| self.card.select_ef(ctx, EF_SIGN.into()))
.and_then(|_| self.card.sign(ctx, digest))
}
pub fn auth_pin_status(&self, ctx: Ctx) -> Result<u8, card::Error> {
self.card.pin_status(ctx, EF_AUTH_PIN)
}
pub fn sign_pin_status(&self, ctx: Ctx) -> Result<u8, card::Error> {
self.card.pin_status(ctx, EF_SIGN_PIN)
}
fn verify_auth_pin(&self, ctx: Ctx, pin: Vec<u8>) -> Result<(), card::Error> {
self.card.verify_pin(ctx, EF_AUTH_PIN, pin)
}
fn verify_sign_pin(&self, ctx: Ctx, pin: Vec<u8>) -> Result<(), card::Error> {
self.card.verify_pin(ctx, EF_SIGN_PIN, pin)
}
}