1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use anyhow::anyhow;
use iso7816::Instruction;

use crate::{App as _, Result};

app_boilerplate!();

impl crate::App for App {
    const RID: &'static [u8] = super::SOLOKEYS_RID;
    const PIX: &'static [u8] = super::PROVISIONER_PIX;
}

impl App {
    // seems to be destructive currently
    // const BOOT_TO_BOOTROM_COMMAND: u8 = 0x51;
    const GENERATE_P256_ATTESTATION: u8 = 0xbc;
    const GENERATE_ED255_ATTESTATION: u8 = 0xbb;
    const GENERATE_X255_ATTESTATION: u8 = 0xb7;
    const BOOT_TO_BOOTROM: u8 = 0x51;
    const GET_UUID: u8 = 0x62;
    const REFORMAT_FS: u8 = 0xbd;
    const STORE_P256_ATTESTATION_CERT: u8 = 0xba;
    const STORE_ED255_ATTESTATION_CERT: u8 = 0xb9;
    const STORE_X255_ATTESTATION_CERT: u8 = 0xb6;
    const STORE_T1_INTERMEDIATE_PUBKEY: u8 = 0xb5;
    const WRITE_FILE: u8 = 0xbf;

    const PATH_ID: [u8; 2] = [0xe1, 0x01];
    const DATA_ID: [u8; 2] = [0xe1, 0x02];

    pub fn generate_trussed_ed255_attestation_key(&mut self) -> Result<[u8; 32]> {
        Ok(self
            .call(Self::GENERATE_ED255_ATTESTATION)?
            .as_slice()
            .try_into()?)
    }

    pub fn generate_trussed_p256_attestation_key(&mut self) -> Result<[u8; 64]> {
        Ok(self
            .call(Self::GENERATE_P256_ATTESTATION)?
            .as_slice()
            .try_into()?)
    }

    pub fn generate_trussed_x255_attestation_key(&mut self) -> Result<[u8; 32]> {
        Ok(self
            .call(Self::GENERATE_X255_ATTESTATION)?
            .as_slice()
            .try_into()?)
    }

    pub fn reformat_filesystem(&mut self) -> Result<()> {
        self.call(Self::REFORMAT_FS).map(drop)
    }

    pub fn store_trussed_ed255_attestation_certificate(&mut self, der: &[u8]) -> Result<()> {
        self.call_with(Self::STORE_ED255_ATTESTATION_CERT, der)
            .map(drop)
    }

    pub fn store_trussed_p256_attestation_certificate(&mut self, der: &[u8]) -> Result<()> {
        self.call_with(Self::STORE_P256_ATTESTATION_CERT, der)
            .map(drop)
    }

    pub fn store_trussed_x255_attestation_certificate(&mut self, der: &[u8]) -> Result<()> {
        self.call_with(Self::STORE_X255_ATTESTATION_CERT, der)
            .map(drop)
    }

    pub fn store_trussed_t1_intermediate_public_key(&mut self, public_key: [u8; 32]) -> Result<()> {
        self.call_with(Self::STORE_T1_INTERMEDIATE_PUBKEY, &public_key)
            .map(drop)
    }

    pub fn boot_to_bootrom(&mut self) -> Result<()> {
        self.call(Self::BOOT_TO_BOOTROM).map(drop)
    }

    pub fn uuid(&mut self) -> Result<u128> {
        let version_bytes = self.call(Self::GET_UUID)?;
        let bytes: &[u8] = &version_bytes;
        bytes
            .try_into()
            .map_err(|_| anyhow::anyhow!("expected 16 byte UUID, got {}", &hex::encode(bytes)))
            .map(u128::from_be_bytes)
    }

    pub fn write_file(&mut self, data: &[u8], path: &str) -> Result<()> {
        if data.len() > 8192 {
            return Err(anyhow!("data too long (8192 byte limit)"));
        }
        if path.as_bytes().len() > 128 {
            return Err(anyhow!("path {} too long (128 byte limit)", path));
        }

        self.call_with(Instruction::Select.into(), &Self::PATH_ID)
            .map(drop)?;
        self.call_with(Instruction::WriteBinary.into(), path.as_bytes())
            .map(drop)?;

        self.call_with(Instruction::Select.into(), &Self::DATA_ID)
            .map(drop)?;
        self.call_with(Instruction::WriteBinary.into(), data)
            .map(drop)?;

        self.call(Self::WRITE_FILE).map(drop)
    }
}