aboutsummaryrefslogtreecommitdiffstats
path: root/cards/cardos_card.py
blob: b6b067bf72cf6b4c80c910d532f8597316f8c519 (plain)
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
110
111
112
113
114
115
116
117
import utils, TLV_utils
from iso_7816_4_card import *
import building_blocks

class CardOS_Card(ISO_7816_4_Card,building_blocks.Card_with_ls):
    DRIVER_NAME = ["CardOS"]
    
    ATRS = [
            ("3bf2180002c10a31fe58c80874", None),
        ]

    APDU_LIFECYCLE = C_APDU("\x00\xCA\x01\x83\x00")
    APDU_PHASE_CONTROL = C_APDU("\x80\x10\x00\x00\x00")
    APDU_LIST_X = C_APDU("\x80\x16\x01\x00\x00")
    LIST_X_DF = 0
    LIST_X_EF = 1
    LS_L_SIZE_TAG = 0x80

    CARDOS_LIFE_CYCLE_STATUS_BYTE_DESCRIPTIONS = [
         (0x10, "operational"),
         (0x20,  "Administration"),
         (0x23, "Personalization"),
         (0x26, "Initialisation"),
         (0x34, "Manufacturing"),
         (0x3F, "Death"),
         (0x29, "Erase in Progress"),
     ]

    STATUS_WORDS = ( {
        "6283": "File is deactivated",
        "6300": "Authentication failed",
        "6581": "EEPROM error, command aborted",
        "6700": "LC invalid",
        "6881": "Logical channel not supported",
        "6981": "Command can not be used for file structure",
        "6982": "Required access right not granted",
        "6983": "BS object blocked",
        "6984": "BS object has invalid format",
        "6985": "No random number available",
        "6986": "No current EF selected",
        "6987": "Key object for SM not found",
        "6988": "Key object used for SM has invalid format",
        "6A80": "Invalid parameters in data field",
        "6A81": "Function/mode not supported",
        "6A82": "File not found",
        "6A83": "Record/object not found",
        "6A84": "Not enough memory in file / in file system available",
        "6A85": "LC does not fit the TLV structure of the data field",
        "6A86": "P1/P2 invalid",
        "6A87": "LC does not fit P1/P2",
        "6A88": "Object not found (GET DATA)",
        "6C00": "LC does not fit the data to be sent (e.g. SM)",
        "6D00": "INS invalid",
        "6E00": "CLA invalid (Hi nibble)",
        "6F00": "Technical error:\n + It was tried to create more than 254 records in a file\n + Package uses SDK version which is not compatible to API version\n + Package contains invalid statements (LOAD EXECUTABLE)",
        "6F81": "File is invalidated because of checksum error (prop.)",
        "6F82": "Not enough memory available in XRAM",
        "6F83": "Transaction error (i.e. command must not be used in transaction)",
        "6F84": "General protection fault (prop.)",
        "6F85": "Internal failure of PK-API (e.g. wrong CCMS format)",
        "6F86": "Key Object not found",
        "6F87": "Chaining error",
        "6FFF": "Internal assertion (invalid internal error)\n + This error is no runtime error, but an internal error which can occur because of a programming error only.",
        "9000": "Command executed correctly",
        "9001": "Command exectued correctly; EEPROM weakness detected (EEPROM written with second trial; the EEPROM area overwritten has a limited lifetime only)",
        "9850": "Overflow using INCREASE / underflow using DECREASE"
    } )
    
    def list_x(self, x):
        "Get a list of x objects, where x is one of 0 (DFs) or 1 (EFs) or 2 (DFs and EFs)"
        ## FIXME I just guessed this information
        result = self.send_apdu(C_APDU(self.APDU_LIST_X, p1=x))
        
        files = []
        unpacked = TLV_utils.unpack(result.data)
        for tag, length, value in unpacked:
            if isinstance(value, list):
                for tag, length, value in value:
                    if tag == 0x86:
                        files.append(value)
            else:
                if tag == 0x86:
                    files.append(value)
        
        return files
    
    def cmd_listdirs(self):
        "List DFs in current DF"
        result = self.list_x(0)
        print "DFs: " + ", ".join([utils.hexdump(a, short=True) for a in result])
    
    def cmd_listfiles(self):
        "List EFs in current DF"
        result = self.list_x(1)
        print "EFs: " + ", ".join([utils.hexdump(a, short=True) for a in result])
    
    def cmd_lifecycle(self):
        "Check the current lifecycle"
        result = self.send_apdu(C_APDU(self.APDU_LIFECYCLE))
        #status = binascii.b2a_hex(result.data)
        for hex, mes in self.CARDOS_LIFE_CYCLE_STATUS_BYTE_DESCRIPTIONS:
          if (int(binascii.b2a_hex(result.data), 16) == hex):
             print "Satus: " +  mes
             break
    
    def cmd_phase_control(self):
        "change lifecycle between Administration and Operational"
        result = self.send_apdu(C_APDU(self.APDU_PHASE_CONTROL))

             
    COMMANDS = {
        "list_dirs": cmd_listdirs,
        "list_files": cmd_listfiles,
        "ls": building_blocks.Card_with_ls.cmd_list,
        "check_lifecycle": cmd_lifecycle, 
        "phase_control": cmd_phase_control,
        }