Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add APPLICATION_OPEN dashboard apdu support #10

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 68 additions & 28 deletions src/dale/default_apdus/default_apdus.py
Original file line number Diff line number Diff line change
@@ -1,63 +1,73 @@
from enum import IntEnum
from dale.base import Command, Response, Factory

from ..utils import lv_digest, l_digest
from ..display import summary, item_str

DEFAULT_CLA = 0xB0

class DefaultClaIns:
DEFAULT_APDU_INS_GET_VERSION = (0xB0, 0x01)
DEFAULT_APDU_INS_GET_SEED_COOKIE = (0xB0, 0x02)
DEFAULT_APDU_INS_STACK_CONSUMPTION = (0xB0, 0x57)
DEFAULT_APDU_INS_APPLICATION_EXIT = (0xB0, 0xA7)
DEFAULT_APDU_INS_APPLICATION_OPEN = (0xE0, 0xD8)

class Ins(IntEnum):
DEFAULT_APDU_INS_GET_VERSION = 0x01
DEFAULT_APDU_INS_GET_SEED_COOKIE = 0x02
DEFAULT_APDU_INS_STACK_CONSUMPTION = 0x57
DEFAULT_APDU_INS_APPLICATION_EXIT = 0xA7
@classmethod
def get_default_instructions(cls):
return [
cls.DEFAULT_APDU_INS_GET_VERSION,
cls.DEFAULT_APDU_INS_GET_SEED_COOKIE,
cls.DEFAULT_APDU_INS_STACK_CONSUMPTION,
cls.DEFAULT_APDU_INS_APPLICATION_EXIT,
cls.DEFAULT_APDU_INS_APPLICATION_OPEN,
]


def valid_ins(ins: int) -> bool:
try:
Ins(ins)
except ValueError:
return False
return True
def is_valid_default_ins(cla: int, ins: int) -> bool:
for instruction in DefaultClaIns.get_default_instructions():
if (cla, ins) == instruction:
return True
return False


def default_ins_to_text(cla: int, ins: int) -> str:
instruction_map = {
DefaultClaIns.DEFAULT_APDU_INS_GET_VERSION: "GET_VERSION",
DefaultClaIns.DEFAULT_APDU_INS_GET_SEED_COOKIE: "GET_SEED_COOKIE",
DefaultClaIns.DEFAULT_APDU_INS_STACK_CONSUMPTION: "STACK_CONSUMPTION",
DefaultClaIns.DEFAULT_APDU_INS_APPLICATION_EXIT: "APPLICATION_EXIT",
DefaultClaIns.DEFAULT_APDU_INS_APPLICATION_OPEN: "APPLICATION_OPEN",
}

INS = {
int(Ins.DEFAULT_APDU_INS_GET_VERSION): 'GET_VERSION',
int(Ins.DEFAULT_APDU_INS_GET_SEED_COOKIE): 'GET_SEED_COOKIE',
int(Ins.DEFAULT_APDU_INS_STACK_CONSUMPTION): 'STACK_CONSUMPTION',
int(Ins.DEFAULT_APDU_INS_APPLICATION_EXIT): 'APPLICATION_EXIT',
}
return instruction_map.get((cla, ins), "UNKNOWN_INSTRUCTION")


class DefaultAPDUsFactory(Factory):

def is_recognized(self, data: bytes, last_one_recognized: bool) -> bool:
if len(data) != 5:
return False
if data[0] != DEFAULT_CLA:
return False

cla = data[0]
ins = data[1]
if not valid_ins(ins):
if not is_valid_default_ins(cla, ins):
return False
else:
return True

def translate_command(self, data: bytes) -> Command:
cla = data[0]
ins = data[1]
if ins == Ins.DEFAULT_APDU_INS_GET_VERSION:
if (cla, ins) == DefaultClaIns.DEFAULT_APDU_INS_GET_VERSION:
return GetVersionCommand(data)
if ins == Ins.DEFAULT_APDU_INS_APPLICATION_EXIT:
if (cla, ins) == DefaultClaIns.DEFAULT_APDU_INS_APPLICATION_EXIT:
return ExitApplicationCommand(data)
if (cla, ins) == DefaultClaIns.DEFAULT_APDU_INS_APPLICATION_OPEN:
return OpenApplicationCommand(data)
else:
raise NotImplementedError


class DefaultAPDUsCommand(Command):
def __init__(self, data: bytes):
super().__init__(data)
self.ins_str = f"Instruction: 0x{self.ins:02x} ({INS[self.ins]})"
self.ins_str = f"CLA: 0x{self.cla:02x}, INS: 0x{self.ins:02x} ({default_ins_to_text(self.cla, self.ins)})"
self.header = f"DEFAULT APDU | {self.ins_str}"

@property
Expand Down Expand Up @@ -144,3 +154,33 @@ def __str__(self):
return "\n".join([
super().__str__(),
])


class OpenApplicationCommand(DefaultAPDUsCommand):
def __init__(self, data: bytes):
super().__init__(data)
self.summary = "Request application opening from Dashboard"
self.name_length = data[4]
self.name = data[4:]

@property
def next(self):
return OpenApplicationResponse

def __str__(self):
return "\n".join([
super().__str__(),
item_str(1, "Name length", self.name_length),
item_str(1, "Name", f"'{self.name.decode()}'"),
])


class OpenApplicationResponse(DefaultAPDUsResponse):
def __init__(self, data):
super().__init__(data)
self.summary = "Dashboard acknowledges the request to open the application"

def __str__(self):
return "\n".join([
super().__str__(),
])
Loading