add new tool pinpad-test.py
This commit is contained in:
@@ -1,3 +1,12 @@
|
||||
2011-12-16 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* tool/gnuk_put_binary_libusb.py (gnuk_token.cmd_select_openpgp):
|
||||
Fix apdu parameter.
|
||||
|
||||
* tool/gnuk_put_binary.py (GnukToken.cmd_select_openpgp): Ditto.
|
||||
|
||||
* tool/pinpad-test.py: New.
|
||||
|
||||
2011-12-14 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* Version 0.16.
|
||||
|
||||
@@ -72,7 +72,7 @@ class GnukToken(object):
|
||||
count += 1
|
||||
|
||||
def cmd_select_openpgp(self):
|
||||
apdu = [0x00, 0xa4, 0x04, 0x0c, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, "cmd_select_openpgp"
|
||||
|
||||
@@ -189,7 +189,7 @@ class gnuk_token:
|
||||
count += 1
|
||||
|
||||
def cmd_select_openpgp(self):
|
||||
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
|
||||
cmd_data = iso7816_compose(0xa4, 0x04, 0x00, "\xD2\x76\x00\x01\x24\x01")
|
||||
sw = self.icc_send_cmd(cmd_data)
|
||||
if len(sw) != 2:
|
||||
raise ValueError, "cmd_select_openpgp"
|
||||
|
||||
187
tool/pinpad-test.py
Executable file
187
tool/pinpad-test.py
Executable file
@@ -0,0 +1,187 @@
|
||||
#! /usr/bin/python
|
||||
|
||||
"""
|
||||
pinpad-test.py - a tool to test pinpad support by card reader.
|
||||
|
||||
Copyright (C) 2011 Free Software Initiative of Japan
|
||||
Author: NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
This file is a part of Gnuk, a GnuPG USB Token implementation.
|
||||
|
||||
Gnuk is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gnuk is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
# Assume only single CCID device is attached to computer with card
|
||||
|
||||
from smartcard.CardType import AnyCardType
|
||||
from smartcard.CardRequest import CardRequest
|
||||
from smartcard.util import toHexString
|
||||
|
||||
CM_IOCTL_GET_FEATURE_REQUEST = (0x42000000 + 3400)
|
||||
FEATURE_VERIFY_PIN_DIRECT = 0x06
|
||||
FEATURE_MODIFY_PIN_DIRECT = 0x07
|
||||
|
||||
class Card(object):
|
||||
def __init__(self, add_a_byte):
|
||||
cardtype = AnyCardType()
|
||||
cardrequest = CardRequest(timeout=1, cardType=cardtype)
|
||||
cardservice = cardrequest.waitforcard()
|
||||
self.connection = cardservice.connection
|
||||
self.verify_ioctl = -1
|
||||
self.modify_ioctl = -1
|
||||
self.another_byte = add_a_byte
|
||||
|
||||
def get_features(self):
|
||||
p = self.connection.control(CM_IOCTL_GET_FEATURE_REQUEST, [])
|
||||
i = 0
|
||||
while i < len(p):
|
||||
code = p[i]
|
||||
l = p[i+1]
|
||||
i = i + 2
|
||||
if l == 4:
|
||||
ioctl = (p[i] << 24) | (p[i+1] << 16) | (p[i+2] << 8) | p[i+3]
|
||||
i = i + l
|
||||
else:
|
||||
i = i + l
|
||||
continue
|
||||
if code == FEATURE_VERIFY_PIN_DIRECT:
|
||||
self.verify_ioctl = ioctl
|
||||
elif code == FEATURE_MODIFY_PIN_DIRECT:
|
||||
self.modify_ioctl = ioctl
|
||||
if self.verify_ioctl == -1:
|
||||
raise ValueError, "Not supported"
|
||||
|
||||
def cmd_select_openpgp(self):
|
||||
apdu = [0x00, 0xa4, 0x04, 0x00, 6, 0xd2, 0x76, 0x00, 0x01, 0x24, 0x01 ]
|
||||
response, sw1, sw2 = self.connection.transmit(apdu)
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, "cmd_select_openpgp"
|
||||
|
||||
def possibly_add_dummy_byte(self):
|
||||
if self.another_byte:
|
||||
return [ 0 ]
|
||||
else:
|
||||
return []
|
||||
|
||||
def cmd_verify_pinpad(self, who):
|
||||
apdu = [0x00, 0x20, 0x00, 0x80+who ]
|
||||
pin_verify = [ 0x00, # bTimeOut
|
||||
0x00, # bTimeOut2
|
||||
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
||||
0x00, # bmPINBlockString
|
||||
0x00, # bmPINLengthFormat
|
||||
15, # wPINMaxExtraDigit Low (PINmax)
|
||||
1, # wPINMaxExtraDigit High (PINmin)
|
||||
0x02, # bEntryValidationCondition
|
||||
0x01, # bNumberMessage
|
||||
0x00, # wLangId Low
|
||||
0x00, # wLangId High
|
||||
0x00, # bMsgIndex
|
||||
0x00, # bTeoPrologue[0]
|
||||
0x00, # bTeoPrologue[1]
|
||||
0x00 # bTeoPrologue[2]
|
||||
]
|
||||
pin_verify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
|
||||
data = self.connection.control(self.verify_ioctl,pin_verify)
|
||||
sw1 = data[0]
|
||||
sw2 = data[1]
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, ("cmd_verify_pinpad %02x %02x" % (sw1, sw2))
|
||||
|
||||
def send_modify_pinpad(self, adpu, command):
|
||||
if self.modify_ioctl == -1:
|
||||
raise ValueError, "Not supported"
|
||||
pin_modify = [ 0x00, # bTimerOut
|
||||
0x00, # bTimerOut2
|
||||
0x82, # bmFormatString: Byte, pos=0, left, ASCII.
|
||||
0x00, # bmPINBlockString
|
||||
0x00, # bmPINLengthFormat
|
||||
0x00, # bInsertionOffsetOld
|
||||
0x00, # bInsertionOffsetNew
|
||||
15, # wPINMaxExtraDigit Low (PINmax)
|
||||
1, # wPINMaxExtraDigit High (PINmin)
|
||||
0x03, # bConfirmPIN: old PIN and new PIN twice
|
||||
0x02, # bEntryValidationCondition
|
||||
0x03, # bNumberMessage
|
||||
0x00, # wLangId Low
|
||||
0x00, # wLangId High
|
||||
0x00, # bMsgIndex1
|
||||
0x01, # bMsgIndex2
|
||||
0x02, # bMsgIndex3
|
||||
0x00, # bTeoPrologue[0]
|
||||
0x00, # bTeoPrologue[1]
|
||||
0x00 # bTeoPrologue[2]
|
||||
]
|
||||
pin_modify += [ len(apdu), 0, 0, 0 ] + apdu + self.possibly_add_dummy_byte()
|
||||
data = self.connection.control(self.modify_ioctl,pin_modify)
|
||||
sw1 = data[0]
|
||||
sw2 = data[1]
|
||||
if not (sw1 == 0x90 and sw2 == 0x00):
|
||||
raise ValueError, ("%s %02x %02x" % (command, sw1, sw2))
|
||||
|
||||
def cmd_reset_retry_counter_pinpad(self, who):
|
||||
apdu = [0x00, 0x2c, 0x02, 0x80+who ]
|
||||
self.send_modify_pinpad(apdu, "cmd_reset_retry_counter_pinpad")
|
||||
|
||||
def cmd_change_reference_data(self, who):
|
||||
apdu = [0x00, 0x24, 0x00, 0x80+who ]
|
||||
self.send_modify_pinpad(apdu, "cmd_change_reference_data")
|
||||
|
||||
|
||||
def main(who, method, add_a_byte):
|
||||
card = Card(add_a_byte)
|
||||
|
||||
card.connection.connect()
|
||||
print "Reader/Token:", card.connection.getReader()
|
||||
print "ATR:", toHexString( card.connection.getATR() )
|
||||
|
||||
card.get_features()
|
||||
card.cmd_select_openpgp()
|
||||
if method == "verify"
|
||||
card.cmd_verify_pinpad(who)
|
||||
elif method == "change"
|
||||
card.cmd_change_reference_data(self, who):
|
||||
elif method == "unblock"
|
||||
card.cmd_reset_retry_counter_pinpad(who)
|
||||
else:
|
||||
raise ValueError, method
|
||||
card.connection.disconnect()
|
||||
|
||||
print "OK."
|
||||
return 0
|
||||
|
||||
BY_ADMIN = 3
|
||||
BY_USER = 1
|
||||
|
||||
if __name__ == '__main__':
|
||||
who = BY_USER
|
||||
method = "verify"
|
||||
add_a_byte = False
|
||||
while len(sys.argv) >= 2:
|
||||
option = sys.argv[1]
|
||||
sys.argv.pop(1)
|
||||
if option == '--admin':
|
||||
who = BY_ADMIN
|
||||
elif option == '--unblock':
|
||||
who = BY_ADMIN
|
||||
method = "unblock"
|
||||
elif option == '--change':
|
||||
method = "change"
|
||||
elif option == '--add':
|
||||
add_a_byte = True
|
||||
else:
|
||||
raise ValueError, option
|
||||
main(who, method, add_a_byte)
|
||||
Reference in New Issue
Block a user