blob: 1c31ddcc4ffb29ed1796f78c36ff0596b5498bff [file] [log] [blame]
Harald Welte34eb5042022-02-21 17:19:28 +01001# coding=utf-8
2"""Partial Support for GlobalPLatform Card Spec (currently 2.1.1)
3
4(C) 2022 by Harald Welte <laforge@osmocom.org>
5
6This program is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18"""
19
20from typing import Optional, List, Dict, Tuple
21from construct import Optional as COptional
22from construct import *
23from bidict import bidict
24from pySim.construct import *
25from pySim.utils import *
26from pySim.filesystem import *
27from pySim.tlv import *
28from pySim.profile import CardProfile
29
30sw_table = {
31 'Warnings': {
32 '6200': 'Logical Channel already closed',
33 '6283': 'Card Life Cycle State is CARD_LOCKED',
34 '6310': 'More data available',
35 },
36 'Execution errors': {
37 '6400': 'No specific diagnosis',
38 '6581': 'Memory failure',
39 },
40 'Checking errors': {
41 '6700': 'Wrong length in Lc',
42 },
43 'Functions in CLA not supported': {
44 '6881': 'Logical channel not supported or active',
45 '6882': 'Secure messaging not supported',
46 },
47 'Command not allowed': {
48 '6982': 'Security Status not satisfied',
49 '6985': 'Conditions of use not satisfied',
50 },
51 'Wrong parameters': {
52 '6a80': 'Incorrect values in command data',
53 '6a81': 'Function not supported e.g. card Life Cycle State is CARD_LOCKED',
54 '6a82': 'Application not found',
55 '6a84': 'Not enough memory space',
56 '6a86': 'Incorrect P1 P2',
57 '6a88': 'Referenced data not found',
58 },
59 'GlobalPlatform': {
60 '6d00': 'Invalid instruction',
61 '6e00': 'Invalid class',
62 },
63 'Application errors': {
64 '9484': 'Algorithm not supported',
65 '9485': 'Invalid key check value',
66 },
67}
68
69# GlobalPlatform 2.1.1 Section 9.1.6
70KeyType = Enum(Byte, des=0x80,
71 rsa_public_exponent_e_cleartex=0xA0,
72 rsa_modulus_n_cleartext=0xA1,
73 rsa_modulus_n=0xA2,
74 rsa_private_exponent_d=0xA3,
75 rsa_chines_remainder_p=0xA4,
76 rsa_chines_remainder_q=0xA5,
77 rsa_chines_remainder_pq=0xA6,
78 rsa_chines_remainder_dpi=0xA7,
79 rsa_chines_remainder_dqi=0xA8,
80 not_available=0xff)
81
82# GlobalPlatform 2.1.1 Section 9.3.3.1
83# example:
84# e0 48
85# c0 04 01708010
86# c0 04 02708010
87# c0 04 03708010
88# c0 04 01018010
89# c0 04 02018010
90# c0 04 03018010
91# c0 04 01028010
92# c0 04 02028010
93# c0 04 03028010
94# c0 04 01038010
95# c0 04 02038010
96# c0 04 03038010
97class KeyInformationData(BER_TLV_IE, tag=0xc0):
98 _construct = Struct('key_identifier'/Byte, 'key_version_number'/Byte,
99 'key_types'/GreedyRange(KeyType))
100class KeyInformation(BER_TLV_IE, tag=0xe0, nested=[KeyInformationData]):
101 pass
102
103# card data sample, returned in response to GET DATA (80ca006600):
104# 66 31
105# 73 2f
106# 06 07
107# 2a864886fc6b01
108# 60 0c
109# 06 0a
110# 2a864886fc6b02020101
111# 63 09
112# 06 07
113# 2a864886fc6b03
114# 64 0b
115# 06 09
116# 2a864886fc6b040215
117
118# GlobalPlatform 2.1.1 Table F-1
119class ObjectIdentifier(BER_TLV_IE, tag=0x06):
120 _construct = GreedyBytes
121class CardManagementTypeAndVersion(BER_TLV_IE, tag=0x60, nested=[ObjectIdentifier]):
122 pass
123class CardIdentificationScheme(BER_TLV_IE, tag=0x63, nested=[ObjectIdentifier]):
124 pass
125class SecureChannelProtocolOfISD(BER_TLV_IE, tag=0x64, nested=[ObjectIdentifier]):
126 pass
127class CardConfigurationDetails(BER_TLV_IE, tag=0x65):
128 _construct = GreedyBytes
129class CardChipDetails(BER_TLV_IE, tag=0x66):
130 _construct = GreedyBytes
131class CardRecognitionData(BER_TLV_IE, tag=0x73, nested=[ObjectIdentifier,
132 CardManagementTypeAndVersion,
133 CardIdentificationScheme,
134 SecureChannelProtocolOfISD,
135 CardConfigurationDetails,
136 CardChipDetails]):
137 pass
138class CardData(BER_TLV_IE, tag=0x66, nested=[CardRecognitionData]):
139 pass
140
141# GlobalPlatform 2.1.1 Table F-2
142class SecureChannelProtocolOfSelectedSD(BER_TLV_IE, tag=0x64, nested=[ObjectIdentifier]):
143 pass
144class SecurityDomainMgmtData(BER_TLV_IE, tag=0x73, nested=[CardManagementTypeAndVersion,
145 CardIdentificationScheme,
146 SecureChannelProtocolOfSelectedSD,
147 CardConfigurationDetails,
148 CardChipDetails]):
149 pass
150
151# GlobalPlatform 2.1.1 Section 9.1.1
152IsdLifeCycleState = Enum(Byte, op_ready=0x01, initialized=0x07, secured=0x0f,
153 card_locked = 0x7f, terminated=0xff)
154
155# GlobalPlatform 2.1.1 Section 9.9.3.1
156class ApplicationID(BER_TLV_IE, tag=0x84):
157 _construct = GreedyBytes
158
159# GlobalPlatform 2.1.1 Section 9.9.3.1
160class SecurityDomainManagementData(BER_TLV_IE, tag=0x73):
161 _construct = GreedyBytes
162
163# GlobalPlatform 2.1.1 Section 9.9.3.1
164class ApplicationProductionLifeCycleData(BER_TLV_IE, tag=0x9f6e):
165 _construct = GreedyBytes
166
167# GlobalPlatform 2.1.1 Section 9.9.3.1
168class MaximumLengthOfDataFieldInCommandMessage(BER_TLV_IE, tag=0x9f65):
169 _construct = GreedyInteger()
170
171# GlobalPlatform 2.1.1 Section 9.9.3.1
172class ProprietaryData(BER_TLV_IE, tag=0xA5, nested=[SecurityDomainManagementData,
173 ApplicationProductionLifeCycleData,
174 MaximumLengthOfDataFieldInCommandMessage]):
175 pass
176
177# GlobalPlatform 2.1.1 Section 9.9.3.1
178class FciTemplate(BER_TLV_IE, tag=0x6f, nested=[ApplicationID, SecurityDomainManagementData,
179 ApplicationProductionLifeCycleData,
180 MaximumLengthOfDataFieldInCommandMessage,
181 ProprietaryData]):
182 pass
183
184class IssuerIdentificationNumber(BER_TLV_IE, tag=0x42):
185 _construct = BcdAdapter(GreedyBytes)
186
187class CardImageNumber(BER_TLV_IE, tag=0x45):
188 _construct = BcdAdapter(GreedyBytes)
189
190class SequenceCounterOfDefaultKvn(BER_TLV_IE, tag=0xc1):
191 _construct = GreedyInteger()
192
193class ConfirmationCounter(BER_TLV_IE, tag=0xc2):
194 _construct = GreedyInteger()
195
196# Collection of all the data objects we can get from GET DATA
197class DataCollection(TLV_IE_Collection, nested=[IssuerIdentificationNumber,
198 CardImageNumber,
199 CardData,
200 KeyInformation,
201 SequenceCounterOfDefaultKvn,
202 ConfirmationCounter]):
203 pass
204
205def decode_select_response(resp_hex: str) -> object:
206 t = FciTemplate()
207 t.from_tlv(h2b(resp_hex))
208 d = t.to_dict()
209 return flatten_dict_lists(d['fci_template'])
210
211# Application Dedicated File of a Security Domain
212class ADF_SD(CardADF):
213 def __init__(self, aid: str, name: str, desc: str):
214 super().__init__(aid=aid, fid=None, sfid=None, name=name, desc=desc)
215 self.shell_commands += [self.AddlShellCommands()]
216
217 @staticmethod
218 def decode_select_response(res_hex: str) -> object:
219 return decode_select_response(res_hex)
220
221 @with_default_category('Application-Specific Commands')
222 class AddlShellCommands(CommandSet):
223 def __init__(self):
224 super().__init__()
225
226 def do_get_data(self, opts):
227 tlv_cls_name = opts.arg_list[0]
228 tlv_cls = DataCollection().members_by_name[tlv_cls_name]
229 (data, sw) = self._cmd.card._scc.get_data(cla=0x80, tag=tlv_cls.tag)
230 ie = tlv_cls()
231 ie.from_tlv(h2b(data))
232 self._cmd.poutput_json(ie.to_dict())
233
234 def complete_get_data(self, text, line, begidx, endidx) -> List[str]:
235 #data_dict = {camel_to_snake(str(x.__name__)): x for x in DataCollection.possible_nested}
236 data_dict = {str(x.__name__): x for x in DataCollection.possible_nested}
237 index_dict = {1: data_dict}
238 return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)
239
240# Card Application of a Security Domain
241class CardApplicationSD(CardApplication):
242 def __init__(self, aid: str, name: str, desc: str):
243 super().__init__(name, adf=ADF_SD(aid, name, desc), sw=sw_table)
244
245# Card Application of Issuer Security Domain
246class CardApplicationISD(CardApplicationSD):
247 # FIXME: ISD AID is not static, but could be different. One can select the empty
248 # application using '00a4040000' and then parse the response FCI to get the ISD AID
249 def __init__(self, aid='a000000003000000'):
250 super().__init__(aid=aid, name='ADF.ISD', desc='Issuer Security Domain')
251
252#class CardProfileGlobalPlatform(CardProfile):
253# ORDER = 23
254#
255# def __init__(self, name='GlobalPlatform'):
256# super().__init__(name, desc='GlobalPlatfomr 2.1.1', cla=['00','80','84'], sw=sw_table)