17 0x04:
"DESACTIVATE FILE",
24 0x24:
"CHANGE REFERENCE DATA",
26 0x26:
"DISABLE VERIFICATION REQUIREMENT",
27 0x28:
"ENABLE VERIFICATION REQUIREMENT",
29 0x2C:
"RESET RETRY COUNTER",
30 0x2D:
"RESET RETRY COUNTER",
31 0x44:
"ACTIVATE FILE",
32 0x46:
"GENERATE ASYMMETRIC KEY PAIR",
33 0x47:
"GENERATE ASYMMETRIC KEY PAIR",
34 0x84:
"GET CHALLENGE",
35 0x86:
"GENERAL AUTHENTICATE",
36 0x87:
"GENERAL AUTHENTICATE",
37 0x88:
"INTERNAL AUTHENTICATE",
38 0xA0:
"SEARCH BINARY",
39 0xA1:
"SEARCH BINARY",
40 0xA2:
"SEARCH RECORD",
54 0xD6:
"UPDATE BINARY",
55 0xD7:
"UPDATE BINARY",
58 0xDC:
"UPDATE RECORD",
59 0xDD:
"UPDATE RECORD",
61 0xE2:
"APPEND RECORD",
65 0xFE:
"TERMINATE CARD USAGE",
69 "a00000039742544659":
"MsGidsAID",
71 "a0000003974349445f0100":
"SC PNP",
72 "a0000001510000":
"GPC",
79 0x3FFF:
"Current application(ADF)",
83 "df1f":
"DO_FILESYSTEMTABLE",
85 "df21":
"DO_CARDAPPS",
87 "df23":
"DO_CMAPFILE",
94 0x6282:
"end of file or record",
95 0x6283:
"card locked",
96 0x63C0:
"warning counter 0",
97 0x63C1:
"warning counter 1",
98 0x63C2:
"warning counter 2",
99 0x63C3:
"warning counter 3",
100 0x63C4:
"warning counter 4",
101 0x63C5:
"warning counter 5",
102 0x63C6:
"warning counter 6",
103 0x63C7:
"warning counter 7",
104 0x63C8:
"warning counter 8",
105 0x63C9:
"warning counter 9",
106 0x6982:
"security status not satisfied",
107 0x6882:
"Secure messaging not supported",
108 0x6985:
"condition of use not satisfied",
109 0x6A80:
"incorrect parameter cmd data field",
110 0x6A81:
"function not suppported",
111 0x6A82:
"file or application not found",
112 0x6A83:
"record not found",
113 0x6A88:
"REFERENCE DATA NOT FOUND",
114 0x6D00:
"unsupported",
118 "5fc101":
"X.509 Certificate for Card Authentication",
119 "5fc102":
"Card Holder Unique Identifier",
120 "5fc103":
"Cardholder Fingerprints",
121 "5fc105":
"X.509 Certificate for PIV Authentication",
122 "5fc106":
"Security Object",
123 "5fc107":
"Card Capability Container",
124 "5fc108":
"Cardholder Facial Image",
125 "5fc10a":
"X.509 Certificate for Digital Signature",
126 "5fc10b":
"X.509 Certificate for Key Management",
127 "5fc10d":
"Retired X.509 Certificate for Key Management 1",
128 "5fc10e":
"Retired X.509 Certificate for Key Management 2",
129 "5fc10f":
"Retired X.509 Certificate for Key Management 3",
133 """Base application"""
135 def __init__(self, aid):
141 def selectResult(self, fci, status, body):
142 return 'selectResult(fci=%s, status=0x%x) = %s\n' %(fci, status, body.hex())
144 def getData(self, fileId, bytes):
145 return 'getData(status=0x%x) = %s\n' %(fileId, bytes.hex())
147 def getDataResult(self, status, body):
148 return 'getDataResult(status=0x%x) = %s\n' %(status, body.hex())
153 def mseResult(self, status, body):
159 def psoResult(self, status, body):
162 def getResponse(self, status, body):
165 def getResponseResult(self, status, body):
168 def verify(self, status, body):
169 return "verify(%s)" % body.hex()
171 def verifyResult(self, status, body):
172 return "verify(%s)" % body.hex()
178 """GlobalPlatform application"""
180 def __init__(self, aid):
187 def selectResult(self, fci, status, body):
188 return 'selectResult(fci=%s, status=0x%x) = %s\n' %(fci, status, body.hex())
190 def getData(self, fileId, bytes):
192 0x42:
'Issuer Identification Number',
193 0x45:
'Card Image Number',
195 0x67:
'Card Capability Information'
198 return 'getData(%s)\n' % tags.get(fileId,
'<unknown 0x%x>' % fileId)
200 def getDataResult(self, status, body):
204 return 'getDataResult(0x%x) = %s\n' %(status, body.hex())
209 def mseResult(self, status, body):
215 def psoResult(self, status, body):
218 def getResponse(self, status, body):
221 def getResponseResult(self, status, body):
226 """PIV application"""
228 def __init__(self, aid):
235 def selectResult(self, selectT, status, body):
240 body = body[2:2+appLen]
248 ret +=
"\tpiv version: %s\n" % body[2:2 + tagLen].hex()
250 subBody = body[2:2 + tagLen]
255 content = subBody.hex()
258 if v.startswith(
'a000000308'):
260 ret +=
'\tCoexistent tag allocation authority: %s\n' % content
263 ret +=
'\tapplication label: %s\n' % body[2:2+tagLen].decode(
'utf8')
265 ret +=
'\tCryptographic algorithms supported: %s\n' % body[2:2+tagLen].hex()
267 rety +=
'\tunknown tag 0x%x\n' % tag
270 ret +=
"\tTODO: selectType %s\n" % selectT
272 body = body[2+tagLen:]
276 def getData(self, fileId, bytes):
277 ret =
"\tfileId=%s(%0.4x)\n" % (FIDs.get(fileId,
""), fileId)
280 return ret +
"\t/!\\ too short !!!!"
287 ret +=
"\tdoId=%0.4x\n"% (bytes[7] * 256 + bytes[8])
296 keyStr =
"key(tag=0x%x len=%d ref=0x%x)=" % (tag, tagLen, keyRef)
301 keyStr +=
"value(tag=0x%x len=%d)"
303 ret +=
"\tDiscovery Object\n"
305 ret +=
"\tBiometric Information Templates (BIT) Group Template\n"
308 tagStr = bytes[7:10].hex()
309 ret +=
'\ttag: %s(%s)\n' % (tagStr, PIV_OIDs.get(tagStr,
'<unknown>'))
312 ret +=
"\tunknown key access(lc=0x%x)\n" % lc
316 def getDataResult(self, status, body):
323 body = body[2:2+appLen]
327 tagBody = body[2:2+tagLen]
329 if self.
lastGetlastGet
in (
'5fc102',):
332 ret +=
'\tFASC-N: %s\n' % tagBody.hex()
334 ret +=
'\tGUID: %s\n' % tagBody.hex()
336 ret +=
'\texpirationDate: %s\n' % tagBody.decode(
'utf8')
338 ret +=
'\tIssuer Asymmetric Signature: %s\n' % tagBody.hex()
340 ret +=
"\tunknown tag=0x%x len=%d content=%s\n" % (tag, tagLen, tagBody.hex())
342 elif self.
lastGetlastGet
in (
'5fc107',):
345 0xf0:
"Card Identifier",
346 0xf1:
"Capability Container version number",
347 0xf2:
"Capability Grammar version number",
348 0xf3:
"Applications CardURL",
350 0xf5:
"Registered Data Model number",
351 0xf6:
"Access Control Rule Table",
353 0xfa:
"Redirection Tag",
354 0xfb:
"Capability Tuples (CTs)",
355 0xfc:
"Status Tuples (STs)",
357 0xe3:
"Extended Application CardURL",
358 0xb4:
"Security Object Buffer",
359 0xfe:
"Error Detection Code"
362 if tag
in capas.keys():
364 ret +=
"\t%s: len=%d %s\n" % (capas[tag], tagLen, tagBody.hex())
366 ret +=
"\tunknown capa tag 0x%x: %s\n" % (tag, tagBody.hex())
368 elif self.
lastGetlastGet ==
'5fc105':
373 ret +=
"\t%s: unimplemented tag=0x%x len=%d content=%s\n" % (self.
lastGetlastGet, tag, tagLen, tagBody.hex())
375 body = body[2+tagLen:]
379 def getResponse(self, status, body):
382 def getResponseResult(self, status, body):
388 def mseResult(self, status, body):
394 def psoResult(self, status, body):
397 def verify(self, status, body):
398 return "verify(%s)" % body.hex()
400 def verifyResult(self, status, body):
401 return "verify(%s)" % body.hex()
407 """GIDS application"""
409 def __init__(self, aid):
416 def parseFcp(self, bytes):
421 body = bytes[2:2+tagLen]
429 tag2Body = body[2:2+tag2Len]
432 ret +=
'\t\tFileDescriptor: %s\n' % tag2Body.hex()
434 ret +=
'\t\tLifeCycleByte: %s\n' % tag2Body.hex()
436 ret +=
'\t\tDF name: %s\n' % tag2Body.encode(
'utf8')
438 ret +=
'\t\tSecurityAttributes: %s\n' % tag2Body.hex()
440 ret +=
'\t\tunhandled tag=0x%x body=%s\n' % (tag2, tag2Body.hex())
442 body = body[2+tag2Len:]
446 def parseFci(self, bytes):
451 body = bytes[2:2+tagLen]
459 tag2Body = body[2:2+tag2Len]
462 ret +=
'\t\tApplication AID: %s\n' % tag2Body.hex()
465 ret +=
'\t\tApplication label: %s\n' % tag2Body.encode(
'utf8')
470 while len(body2) > 2:
477 tokens.append(
'mutualAuthSymAlgo')
479 tokens.append(
'extAuthSymAlgo')
481 tokens.append(
'keyEstabIntAuthECC')
484 body2 = body2[2+tag3Len:]
486 ret +=
'\t\tDiscretionary data objects: %s\n' %
",".join(tokens)
488 ret +=
'\t\tunhandled tag=0x%x body=%s\n' % (tag2, tag2Body.hex())
490 body = body[2+tag2Len:]
495 def selectResult(self, selectT, status, body):
501 elif selectT ==
'FCI':
504 return '\tselectResult(fci=%s, status=0x%x) = %s\n' % (selectT, status, body.hex())
506 def getData(self, fileId, bytes):
512 doStr = bytes[7:7+tagLen].hex()
513 ret =
'\tDO=%s\n' % DOs.get(doStr,
"<%s>" % doStr)
516 ret =
'\tunknown tag=0%x len=%d v=%s' % (tag, tagLen, bytes[7:7+tagLen].hex())
520 def getDataResult(self, status, body):
527 ret += '\ttag=0x%x len=%d content=%s\n' % (tag, tagLen, body[2:2+tagLen].hex())
529 body = body[2+tagLen:]
536 def mseResult(self, status, body):
539 def getResponse(self, status, body):
542 def getResponseResult(self, status, body):
548 def psoResult(self, status, body):
553 def createAppByAid(aid):
554 if aid
in (
"a000000308",
'a00000030800001000',):
557 elif aid
in (
'a00000039742544659',):
560 elif aid
in (
'a0000001510000',):
566 def getErrorCode(status):
568 return "%d more bytes" % (status & 0xff)
570 return ERROR_CODES.get(status,
"<unknown>")
572 if __name__ ==
'__main__':
573 if len(sys.argv) > 1:
574 fin = open(sys.argv[1],
"r")
581 lastSelectFCI =
False
585 for l
in fin.readlines():
596 recvKey =
'pbRecvBuffer: { '
598 pos = l.find(recvKey)
603 pos2 = l.find(
' }', pos)
605 print(
"line %d: invalid recvBuffer")
610 sendKey =
'pbSendBuffer: { '
611 pos = l.find(sendKey)
616 pos2 = l.find(
' }', pos)
618 print(
"line %d: invalid sendBuffer")
624 bytes = codecs.decode(body,
'hex')
626 (cla, ins, p1, p2) = bytes[0:4]
627 cmdName = CMD_NAMES.get(ins,
"<COMMAND 0x%x>" % ins)
630 if cmdName ==
"SELECT":
635 print(
"\tselectByFID: %0.2x%0.2x" % (bytes[i], bytes[i+1]))
639 aid = bytes[i:i+lc].hex()
640 lastSelect = AIDs.get(aid,
'<unknown %s>' % aid)
641 print(
"\tselectByAID: %s(%s)" % (aid, lastSelect))
653 if not currentApp
or currentApp.getAID() != aid:
654 currentApp = createAppByAid(aid)
657 elif cmdName ==
"VERIFY":
659 P2_DATA_QUALIFIER = {
660 0x00:
"Card global password",
662 0x80:
"Application password",
663 0x81:
"Application resetting password",
664 0x82:
"Application security status resetting code",
669 pin =
", pin='" + bytes[5:5+lc-2].decode(
'utf8)') +
"'"
671 print(
"\t%s%s" % (P2_DATA_QUALIFIER.get(p2,
"<unknown>"), pin))
673 elif cmdName ==
"GET DATA":
675 fileId = p1 * 256 + p2
677 ret = currentApp.getData(fileId, bytes)
680 elif cmdName ==
"GET RESPONSE":
687 elif cmdName ==
"MSE":
688 ret = currentApp.mse(bytes[5:5+lc])
691 elif cmdName ==
"PSO":
692 ret = currentApp.pso(bytes[5:5+lc])
695 print(
'handle %s' % cmdName)
704 status = bytes[-1] + bytes[-2] * 256
706 print(
"status=0x%0.4x(%s)" % (status, getErrorCode(status)))
712 if lastCmd ==
"SELECT":
713 ret = currentApp.selectResult(lastSelectT, status, body)
714 elif lastCmd ==
"GET DATA":
715 ret = currentApp.getDataResult(status, body)
716 elif lastCmd ==
"MSE":
717 ret = currentApp.mseResult(status, body)
718 elif lastCmd ==
"PSO":
719 ret = currentApp.psoResult(status, body)
720 elif lastCmd ==
"GET RESPONSE":
721 ret = currentApp.getResponseResult(status, body)
722 elif lastCmd ==
"VERIFY":
723 ret = currentApp.verifyResult(status, body)
def parseFci(self, bytes)
def parseFcp(self, bytes)