def test_CAPDU(self): a = C_APDU(1, 2, 3, 4) # case 1 b = C_APDU(1, 2, 3, 4, 5) # case 2 c = C_APDU((1, 2, 3), cla = 0x23, data = "hallo") # case 3 d = C_APDU(1, 2, 3, 4, 2, 4, 6, 0) # case 4 print() print(a) print(b) print(c) print(d) print() print(repr(a)) print(repr(b)) print(repr(c)) print(repr(d)) print() for i in a, b, c, d: print(hexdump(i.render())) print() g = C_APDU(0x00, 0xb0, 0x9c, 0x00, 0x00, 0x00, 0x00) #case 2 extended length print() print(g) print(repr(g)) print(hexdump(g.render())) h = C_APDU('\x0c\x2a\x00\xbe\x00\x01\x5f\x87\x82\x01\x51\x01\xf0\xa2\x21\xa1\x36\x27\xb1\x30\x31\x3e\xd0\x97\x09\xb5\xde\x73\x5e\x29\x90\xce\xf1\x3d\x8a\xfd\xe7\x92\xe5\xa4\x70\xb9\x5d\x31\xe2\x34\xe7\xe2\x06\x13\x17\x7a\x3e\xca\x06\x39\x24\x2e\x75\x8c\x29\x6d\xd8\xa3\x1b\x1a\x68\x58\xd0\x1a\x98\xd4\xd8\x19\x50\xe9\x1b\x3c\xd1\xfd\x10\x53\x5b\xf2\x3b\xff\x4a\xf6\x05\xd0\x72\xad\xae\xaa\x93\x1a\x0a\x90\xc8\xa1\xb1\xf1\x0a\xba\x5b\xd2\x23\x38\xf8\x9a\x38\x9e\xa2\x04\x8b\xcb\x8b\x8b\xc0\x80\xd9\x2a\x04\x47\x26\x83\xda\xfe\x57\x68\x6b\x00\xb9\xa2\xea\x96\xf2\x07\x7f\xc5\x9c\xee\xbe\xf3\x81\xbf\x24\x19\x1e\x49\x1e\x9a\x85\x8f\x34\xcb\x1a\x23\xae\x6d\x7f\xa4\xb6\x7b\x60\x5d\x56\x79\x1c\xec\x18\xcc\x09\xdb\xb2\xbb\xf4\x31\xee\x08\x54\x26\xd5\xde\x99\xfa\x43\xa2\x49\x8e\x60\xc0\xaa\x4f\xfd\xf7\xe5\xc8\x89\x43\x5e\x11\xa2\x28\xc4\x92\x11\xda\xba\xe4\x91\xec\x04\xc9\x2c\xbd\x91\x6a\x5e\x7e\xb9\x85\xa2\xfa\x07\xc9\x47\x24\xa4\x3b\x63\xef\x75\x65\xef\xaf\xac\x22\x75\x99\x8b\x19\xde\x95\x76\xc9\xc8\xbc\x30\x23\x48\x07\x28\x19\x1e\x49\x9e\xcb\x99\xc3\x48\xdd\x1d\x0f\x44\x62\x64\x2a\x19\x7b\xeb\xee\xdf\xa1\xa6\xae\x87\x6d\x93\x36\x2d\x35\x8f\xd9\x61\x73\xef\x2d\x39\xb5\xc5\xe2\x75\x4b\x63\x0b\x41\x94\x8c\xbb\x55\xf6\x98\x5f\x9c\x07\xca\xe3\x15\xe4\xe6\x93\xd0\xa3\x9b\x22\xfa\x62\x18\xc5\x63\xfa\x2d\x57\xbb\x29\x2d\x57\x10\xd3\x0c\x05\x80\x15\x27\x4b\xc0\x84\x23\x62\x22\x6b\xae\x39\xa2\x8f\x55\xac\x8e\x08\x34\x46\xcc\x83\xf9\x9d\x2a\x75\x00\x00') print() print(h) print(repr(h))
def test_CAPDU(self): a = C_APDU(1, 2, 3, 4) # case 1 b = C_APDU(1, 2, 3, 4, 5) # case 2 c = C_APDU((1, 2, 3), cla=0x23, data="hallo") # case 3 d = C_APDU(1, 2, 3, 4, 2, 4, 6, 0) # case 4 print() print(a) print(b) print(c) print(d) print() print(repr(a)) print(repr(b)) print(repr(c)) print(repr(d)) print() for i in a, b, c, d: print(hexdump(i.render())) # case 2 extended length print() g = C_APDU(0x00, 0xb0, 0x9c, 0x00, 0x00, 0x00, 0x00) print() print(g) print(repr(g)) print(hexdump(g.render())) h = C_APDU('\x0c\x2a\x00\xbe\x00\x01\x5f\x87\x82\x01\x51\x01\xf0\xa2' '\x21\xa1\x36\x27\xb1\x30\x31\x3e\xd0\x97\x09\xb5\xde\x73' '\x5e\x29\x90\xce\xf1\x3d\x8a\xfd\xe7\x92\xe5\xa4\x70\xb9' '\x5d\x31\xe2\x34\xe7\xe2\x06\x13\x17\x7a\x3e\xca\x06\x39' '\x24\x2e\x75\x8c\x29\x6d\xd8\xa3\x1b\x1a\x68\x58\xd0\x1a' '\x98\xd4\xd8\x19\x50\xe9\x1b\x3c\xd1\xfd\x10\x53\x5b\xf2' '\x3b\xff\x4a\xf6\x05\xd0\x72\xad\xae\xaa\x93\x1a\x0a\x90' '\xc8\xa1\xb1\xf1\x0a\xba\x5b\xd2\x23\x38\xf8\x9a\x38\x9e' '\xa2\x04\x8b\xcb\x8b\x8b\xc0\x80\xd9\x2a\x04\x47\x26\x83' '\xda\xfe\x57\x68\x6b\x00\xb9\xa2\xea\x96\xf2\x07\x7f\xc5' '\x9c\xee\xbe\xf3\x81\xbf\x24\x19\x1e\x49\x1e\x9a\x85\x8f' '\x34\xcb\x1a\x23\xae\x6d\x7f\xa4\xb6\x7b\x60\x5d\x56\x79' '\x1c\xec\x18\xcc\x09\xdb\xb2\xbb\xf4\x31\xee\x08\x54\x26' '\xd5\xde\x99\xfa\x43\xa2\x49\x8e\x60\xc0\xaa\x4f\xfd\xf7' '\xe5\xc8\x89\x43\x5e\x11\xa2\x28\xc4\x92\x11\xda\xba\xe4' '\x91\xec\x04\xc9\x2c\xbd\x91\x6a\x5e\x7e\xb9\x85\xa2\xfa' '\x07\xc9\x47\x24\xa4\x3b\x63\xef\x75\x65\xef\xaf\xac\x22' '\x75\x99\x8b\x19\xde\x95\x76\xc9\xc8\xbc\x30\x23\x48\x07' '\x28\x19\x1e\x49\x9e\xcb\x99\xc3\x48\xdd\x1d\x0f\x44\x62' '\x64\x2a\x19\x7b\xeb\xee\xdf\xa1\xa6\xae\x87\x6d\x93\x36' '\x2d\x35\x8f\xd9\x61\x73\xef\x2d\x39\xb5\xc5\xe2\x75\x4b' '\x63\x0b\x41\x94\x8c\xbb\x55\xf6\x98\x5f\x9c\x07\xca\xe3' '\x15\xe4\xe6\x93\xd0\xa3\x9b\x22\xfa\x62\x18\xc5\x63\xfa' '\x2d\x57\xbb\x29\x2d\x57\x10\xd3\x0c\x05\x80\x15\x27\x4b' '\xc0\x84\x23\x62\x22\x6b\xae\x39\xa2\x8f\x55\xac\x8e\x08' '\x34\x46\xcc\x83\xf9\x9d\x2a\x75\x00\x00') print() print(h) print(repr(h))
def run(self): """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ while True : (size, msg) = self.__recvFromVPICC() if not size: logging.warning("Error in communication protocol (missing size parameter)") elif size == VPCD_CTRL_LEN: if msg == chr(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == chr(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == chr(VPCD_CTRL_RESET): logging.info("Reset") self.os.reset() elif msg == chr(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) answer = self.os.execute(msg) logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), hexdump(answer)) self.__sendToVPICC(answer)
def protect_result(self, sw, unprotected_result): """ Protect a plain response APDU by Secure Messaging """ logging.info("Unprotected Response Data:\n" + hexdump(unprotected_result)) return self.current_SE.protect_response(sw, unprotected_result)
def test_RAPDU(self): e = R_APDU(0x90, 0) f = R_APDU("foo\x67\x00") print() print(e) print(f) print() print(repr(e)) print(repr(f)) print() for i in e, f: print(hexdump(i.render()))
def run(self): """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ while True: try: (size, msg) = self.__recvFromVPICC() except socket.error as e: if not self.host: logging.info("Waiting for vpcd on port " + str(self.port)) (self.sock, address) = self.server_sock.accept() continue else: sys.exit() if not size: logging.warning("Error in communication protocol (missing \ size parameter)") elif size == VPCD_CTRL_LEN: if msg == inttostring(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == inttostring(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == inttostring(VPCD_CTRL_RESET): logging.info("Reset") self.os.reset() elif msg == inttostring(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) answer = self.os.execute(msg) logging.info("Response APDU (%d bytes):\n %s\n", len(answer), hexdump(answer, indent=2)) self.__sendToVPICC(answer)
def execute(self, msg): def notImplemented(*argz, **args): """ If an application tries to use a function which is not implemented by the currently emulated smartcard we raise an exception which should result in an appropriate response APDU being passed to the application. """ raise SwError(SW["ERR_INSNOTSUPPORTED"]) logging.info("Command APDU (%d bytes):\n %s", len(msg), hexdump(msg, indent=2)) try: c = C_APDU(msg) logging.debug("%s", str(c)) except ValueError as e: logging.warning(str(e)) return self.formatResult(False, 0, b"", SW["ERR_INCORRECTPARAMETERS"], False) # Handle Class Byte # {{{ class_byte = c.cla SM_STATUS = None logical_channel = 0 command_chaining = 0 header_authentication = 0 # Ugly Hack for OpenSC-explorer if (class_byte == 0xb0): logging.debug("Open SC APDU") SM_STATUS = "No SM" # If Bit 8,7,6 == 0 then first industry values are used if (class_byte & 0xE0 == 0x00): # Bit 1 and 2 specify the logical channel logical_channel = class_byte & 0x03 # Bit 3 and 4 specify secure messaging secure_messaging = class_byte >> 2 secure_messaging &= 0x03 if (secure_messaging == 0x00): SM_STATUS = "No SM" elif (secure_messaging == 0x01): SM_STATUS = "Proprietary SM" # Not supported ? elif (secure_messaging == 0x02): SM_STATUS = "Standard SM" elif (secure_messaging == 0x03): SM_STATUS = "Standard SM" header_authentication = 1 # If Bit 8,7 == 01 then further industry values are used elif (class_byte & 0x0C == 0x0C): # Bit 1 to 4 specify logical channel. 4 is added, value range is # from four to nineteen logical_channel = class_byte & 0x0f logical_channel += 4 # Bit 6 indicates secure messaging secure_messaging = class_byte >> 6 if (secure_messaging == 0x00): SM_STATUS = "No SM" elif (secure_messaging == 0x01): SM_STATUS = "Standard SM" else: # Bit 8 is set to 1, which is not specified by ISO 7816-4 SM_STATUS = "Proprietary SM" # In both cases Bit 5 specifies command chaining command_chaining = class_byte >> 5 command_chaining &= 0x01 # }}} sm = False try: if SM_STATUS == "Standard SM" or SM_STATUS == "Proprietary SM": c = self.SAM.parse_SM_CAPDU(c, header_authentication) logging.info("Decrypted APDU:\n%s", str(c)) sm = True sw, result = self.ins2handler.get(c.ins, notImplemented)(c.p1, c.p2, c.data) answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, sm) except SwError as e: logging.debug(traceback.format_exc().rstrip()) logging.info(e.message) sw = e.sw result = b"" answer = self.formatResult(False, 0, result, sw, sm) return answer
def run(self, mode): # MODIFIED ARGUMENTS """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ # ADDED CODE SECTION IN ORDER TO INTEGRATE ESP32 TO GNUPG STARTS HERE global command # The command APDU global response # The response APDU global condCommand # Condition to wait until a new APDU command arrives global condResponse # Condition to wait until a response is available global newCommand # Flag for the handler that there is a new command global processing # Flag for the run function that the processing has finished global err # Flag for the run function that an error happened condCommand = threading.Condition() condResponse = threading.Condition() # ADDED CODE SECTION ENDS HERE while True: try: (size, msg) = self.__recvFromVPICC() except socket.error as e: if not self.host: logging.info("Waiting for vpcd on port " + str(self.port)) (self.sock, address) = self.server_sock.accept() continue else: sys.exit() # ADDED CODE SECTION IN ORDER TO INTEGRATE ESP32 TO GNUPG STARTS HERE newCommand = 0 processing = 0 command = "" response = "" err = 0 # ADDED CODE SECTION ENDS HERE if not size: logging.warning("Error in communication protocol (missing \ size parameter)") elif size == VPCD_CTRL_LEN: if msg == chr(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == chr(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == chr(VPCD_CTRL_RESET): logging.info("Reset") # ADDED CODE SECTION IN ORDER TO INTEGRATE ESP32 TO GNUPG STARTS HERE if (mode == "esp"): with condCommand: command = '\x00\x55\x00\x00\x00' # Custom command INS to reset newCommand = 1 processing = 1 condCommand.notify() with condResponse: while (processing == 1): condResponse.wait() # ADDED CODE SECTION ENDS HERE self.os.reset() elif msg == chr(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) # ADDED CODE SECTION IN ORDER TO INTEGRATE ESP32 TO GNUPG STARTS HERE if (mode == "esp"): with condCommand: command = msg newCommand = 1 processing = 1 condCommand.notify() with condResponse: while (processing == 1): condResponse.wait(0) if (err == 0): self.__sendToVPICC(response) else: # ESP32 was probably disconnected sys.exit() # Terminate execution else: # ADDED CODE SECTION ENDS HERE answer = self.os.execute(msg) logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), hexdump(answer)) self.__sendToVPICC(answer)
def execute(self, msg): def notImplemented(*argz, **args): """ If an application tries to use a function which is not implemented by the currently emulated smartcard we raise an exception which should result in an appropriate response APDU being passed to the application. """ raise SwError(SW["ERR_INSNOTSUPPORTED"]) logging.info("Command APDU (%d bytes):\n %s", len(msg), hexdump(msg, indent=2)) try: c = C_APDU(msg) logging.debug("%s", str(c)) except ValueError as e: logging.warning(str(e)) return self.formatResult(False, 0, b"", SW["ERR_INCORRECTPARAMETERS"], False) # Handle Class Byte # {{{ class_byte = c.cla SM_STATUS = None logical_channel = 0 command_chaining = 0 header_authentication = 0 # Ugly Hack for OpenSC-explorer if(class_byte == 0xb0): logging.debug("Open SC APDU") SM_STATUS = "No SM" # If Bit 8,7,6 == 0 then first industry values are used if (class_byte & 0xE0 == 0x00): # Bit 1 and 2 specify the logical channel logical_channel = class_byte & 0x03 # Bit 3 and 4 specify secure messaging secure_messaging = class_byte >> 2 secure_messaging &= 0x03 if (secure_messaging == 0x00): SM_STATUS = "No SM" elif (secure_messaging == 0x01): SM_STATUS = "Proprietary SM" # Not supported ? elif (secure_messaging == 0x02): SM_STATUS = "Standard SM" elif (secure_messaging == 0x03): SM_STATUS = "Standard SM" header_authentication = 1 # If Bit 8,7 == 01 then further industry values are used elif (class_byte & 0x0C == 0x0C): # Bit 1 to 4 specify logical channel. 4 is added, value range is # from four to nineteen logical_channel = class_byte & 0x0f logical_channel += 4 # Bit 6 indicates secure messaging secure_messaging = class_byte >> 6 if (secure_messaging == 0x00): SM_STATUS = "No SM" elif (secure_messaging == 0x01): SM_STATUS = "Standard SM" else: # Bit 8 is set to 1, which is not specified by ISO 7816-4 SM_STATUS = "Proprietary SM" # In both cases Bit 5 specifies command chaining command_chaining = class_byte >> 5 command_chaining &= 0x01 # }}} sm = False try: if SM_STATUS == "Standard SM" or SM_STATUS == "Proprietary SM": c = self.SAM.parse_SM_CAPDU(c, header_authentication) logging.info("Decrypted APDU:\n%s", str(c)) sm = True sw, result = self.ins2handler.get(c.ins, notImplemented)(c.p1, c.p2, c.data) answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, sm) except SwError as e: logging.debug(traceback.format_exc().rstrip()) logging.info(e.message) sw = e.sw result = b"" answer = self.formatResult(False, 0, result, sw, sm) return answer
expected = "$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL" if result != expected: raise RuntimeError("self-test failed") # crypt 4 (unicode) result = crypt(u'\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2', '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ') expected = '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ' if result != expected: raise RuntimeError("self-test failed") print "PBKDF2 self test successfull" if __name__ == "__main__": too_short = binascii.a2b_hex("".join("89 45 19 BF".split())) padded = append_padding(8, too_short) print "Padded data: " + hexdump(padded) unpadded = strip_padding(8, padded) print "Without padding: " + hexdump(unpadded) teststring = "DEADBEEFistatsyksdvhwohfwoehcowc8hw8rogfq8whv75tsgohsav8wress" foo = append_padding(16, teststring) assert (strip_padding(16, foo) == teststring) testpass = "******" protectedString = protect_string(teststring, testpass) unprotectedString = read_protected_string(protectedString, testpass) assert (teststring == unprotectedString) #test_pbkdf2()
result = crypt("dcl", "tUsch7fU", iterations=13) expected = "$p5k2$d$tUsch7fU$nqDkaxMDOFBeJsTSfABsyn.PYUXilHwL" if result != expected: raise RuntimeError("self-test failed") # crypt 4 (unicode) result = crypt(u'\u0399\u03c9\u03b1\u03bd\u03bd\u03b7\u03c2', '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ') expected = '$p5k2$$KosHgqNo$9mjN8gqjt02hDoP0c2J0ABtLIwtot8cQ' if result != expected: raise RuntimeError("self-test failed") print "PBKDF2 self test successfull" if __name__ == "__main__": too_short = binascii.a2b_hex("".join("89 45 19 BF".split())) padded = append_padding(8, too_short) print "Padded data: " + hexdump(padded) unpadded = strip_padding(8, padded) print "Without padding: " + hexdump(unpadded) teststring = "DEADBEEFistatsyksdvhwohfwoehcowc8hw8rogfq8whv75tsgohsav8wress" foo = append_padding(16, teststring) assert(strip_padding(16, foo) == teststring) testpass = "******" protectedString = protect_string(teststring, testpass) unprotectedString = read_protected_string(protectedString, testpass) assert(teststring == unprotectedString) #test_pbkdf2()
def logAPDU(self, parsed, unparsed): if (self.logunparsed): logging.info("Unparsed APDU:\n%s", hexdump(unparsed)) else: logging.info("Parsed APDU:\n%s", str(parsed))