This commit is contained in:
NIIBE Yutaka
2012-06-26 17:59:24 +09:00
parent 1118cd030a
commit a41476ab32
19 changed files with 842 additions and 0 deletions

View File

@@ -1,3 +1,7 @@
2012-06-26 Niibe Yutaka <gniibe@fsij.org>
* test: New.
2012-06-25 Niibe Yutaka <gniibe@fsij.org>
* tool/usb_strings.py: New.

15
test/README Normal file
View File

@@ -0,0 +1,15 @@
This is functionality test suite for Gnuk.
You need python-nose, python-freshen, and python-crypto as well as
python-usb.
Type:
$ nosetests --with-freshen .
or
$ nosetests -v --with-freshen .
to run the test suite.

View File

@@ -0,0 +1,79 @@
Feature: confirm empty token
In order to start tests
A token should be empty (no data, no keys)
Scenario: data object Login
When requesting login data: 5e
Then you should get NULL
Scenario: data object Name
When requesting name: 5b
Then you should get NULL
Scenario: data object Language preference
When requesting anguage preference: 5f2d
Then you should get NULL
Scenario: data object Sex
When requesting sex: 5f35
Then you should get NULL
Scenario: data object URL
When requesting URL: 5f50
Then you should get NULL
Scenario: data object ds counter
When requesting ds counter: 93
Then you should get: \x00\x00\x00
Scenario: data object pw1 status bytes
When requesting pw1 status bytes: c4
Then you should get: \x00\x7f\x7f\x7f\x03\x03\x03
Scenario: data object finger print 0
When requesting finger print: c5
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Scenario: data object finger print 1
When requesting finger print: c7
Then you should get NULL
Scenario: data object finger print 2
When requesting finger print: c8
Then you should get NULL
Scenario: data object finger print 3
When requesting finger print: c9
Then you should get NULL
Scenario: data object CA finger print 0
When requesting finger print: c6
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Scenario: data object CA finger print 1
When requesting finger print: ca
Then you should get NULL
Scenario: data object CA finger print 2
When requesting finger print: cb
Then you should get NULL
Scenario: data object CA finger print 3
When requesting finger print: cc
Then you should get NULL
Scenario: data object date/time of key pair 0
When requesting date/time of key pair: cd
Then you should get: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
Scenario: data object date/time of key pair 1
When requesting date/time of key pair: ce
Then you should get NULL
Scenario: data object date/time of key pair 2
When requesting date/time of key pair: cf
Then you should get NULL
Scenario: data object date/time of key pair 3
When requesting date/time of key pair: d0
Then you should get NULL

View File

@@ -0,0 +1,15 @@
Feature: confirm empty token
In order to start tests
A token should be empty (no pass phrase)
Scenario: verify PW1 factory setting (1)
Given cmd_verify with 1 and "123456"
Then it should get success
Scenario: verify PW1 factory setting (2)
Given cmd_verify with 2 and "123456"
Then it should get success
Scenario: verify PW3 factory setting
Given cmd_verify with 3 and "12345678"
Then it should get success

View File

@@ -0,0 +1,27 @@
Feature: command GET DATA
In order to conform OpenPGP card 2.0 specification
A token should support all mandatory features of the specification
Scenario: data object historical bytes
When requesting historical bytes: 5f52
Then you should get: \x00\x31\x84\x73\x80\x01\x80\x00\x90\x00
Scenario: data object extended capabilities
When requesting extended capabilities: c0
Then you should get: \x30\x00\x00\x00\x00\x00\x00\xff\x01\x00
Scenario: data object algorithm attributes 1
When requesting algorithm attributes 1: c1
Then you should get: \x01\x08\x00\x00\x20\x00
Scenario: data object algorithm attributes 2
When requesting algorithm attributes 2: c2
Then you should get: \x01\x08\x00\x00\x20\x00
Scenario: data object algorithm attributes 3
When requesting algorighm attributes 3: c3
Then you should get: \x01\x08\x00\x00\x20\x00
Scenario: data object AID
When requesting AID: 4f
Then data should match: \xd2\x76\x00\x01\x24\x01\x02\x00......\x00\x00

View File

@@ -0,0 +1,63 @@
Feature: setup pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: setup PW1 (admin-less mode)
Given cmd_change_reference_data with 1 and "123456user pass phrase"
Then it should get success
Scenario: verify PW1 (1)
Given cmd_verify with 1 and "user pass phrase"
Then it should get success
Scenario: verify PW1 (2)
Given cmd_verify with 2 and "user pass phrase"
Then it should get success
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "user pass phrase"
Then it should get success
Scenario: setup reset code (in admin-less mode)
Given cmd_put_data with d3 and "example reset code 000"
Then it should get success
Scenario: reset pass phrase by reset code (in admin-less mode)
Given cmd_reset_retry_counter with 0 and "example reset code 000new user pass phrase"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "new user pass phrase"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "new user pass phrase"
Then it should get success
Scenario: verify PW3 (admin-less mode) again
Given cmd_verify with 3 and "new user pass phrase"
Then it should get success
Scenario: setup PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "new user pass phraseadmin pass phrase"
Then it should get success
Scenario: verify PW3 (admin-full mode)
Given cmd_verify with 3 and "admin pass phrase"
Then it should get success
Scenario: setup reset code (in admin-full mode)
Given cmd_put_data with d3 and "another reset code 000"
Then it should get success
Scenario: reset pass phrase by reset code (in admin-full mode)
Given cmd_reset_retry_counter with 0 and "another reset code 000another user pass phrase"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "another user pass phrase"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,27 @@
Feature: personalize token write
In order to use a token
A token should be personalized with name, sex, url, etc.
Scenario: data object Login
Given cmd_put_data with 5e and "gpg_user"
Then it should get success
Scenario: data object Name
Given cmd_put_data with 5b and "GnuPG User"
Then it should get success
Scenario: data object Language preference
Given cmd_put_data with 5f2d and "ja"
Then it should get success
Scenario: data object Sex
Given cmd_put_data with 5f35 and "1"
Then it should get success
Scenario: data object URL
Given cmd_put_data with 5f50 and "http://www.fsij.org/gnuk/"
Then it should get success
Scenario: data object pw1 status bytes
Given cmd_put_data with c4 and "\x01"
Then it should get success

View File

@@ -0,0 +1,27 @@
Feature: personalize token read
In order to use a token
A token should be personalized with name, sex, url, etc.
Scenario: data object Login
When requesting login data: 5e
Then you should get: gpg_user
Scenario: data object Name
When requesting name: 5b
Then you should get: GnuPG User
Scenario: data object Language preference
When requesting anguage preference: 5f2d
Then you should get: ja
Scenario: data object Sex
When requesting sex: 5f35
Then you should get: 1
Scenario: data object URL
When requesting URL: 5f50
Then you should get: http://www.fsij.org/gnuk/
Scenario: data object pw1 status bytes
When requesting pw1 status bytes: c4
Then you should get: \x01\x7f\x7f\x7f\x03\x03\x03

View File

@@ -0,0 +1,18 @@
Feature: import keys to token
In order to use a token
A token should have keys
Scenario: importing OPENPGP.1 key (sign)
Given a RSA key pair 0
And importing it to the token as OPENPGP.1
Then it should get success
Scenario: importing OPENPGP.2 key (decrypt)
Given a RSA key pair 1
And importing it to the token as OPENPGP.2
Then it should get success
Scenario: importing OPENPGP.3 key (authentication)
Given a RSA key pair 2
And importing it to the token as OPENPGP.3
Then it should get success

View File

@@ -0,0 +1,39 @@
Feature: key removal
In order to use a token
A token should have keys
Scenario: remove OPENPGP.1 key (sign)
When removing a key OPENPGP.1
Then it should get success
Scenario: remove OPENPGP.2 key (decrypt)
When removing a key OPENPGP.2
Then it should get success
Scenario: remove OPENPGP.3 key (authentication)
When removing a key OPENPGP.3
Then it should get success
Scenario: remove data object Finger print sig
Given cmd_put_data with c7 and ""
Then it should get success
Scenario: remove data object Finger print dec
Given cmd_put_data with c8 and ""
Then it should get success
Scenario: remove data object Finger print aut
Given cmd_put_data with c9 and ""
Then it should get success
Scenario: remove data object keygeneration data/time sig
Given cmd_put_data with ce and ""
Then it should get success
Scenario: remove data object keygeneration data/time dec
Given cmd_put_data with cf and ""
Then it should get success
Scenario: remove data object keygeneration data/time aut
Given cmd_put_data with d0 and ""
Then it should get success

View File

@@ -0,0 +1,27 @@
Feature: removal of data objects
In order to use a token
A token should have personalized data
Scenario: remove data object Login
Given cmd_put_data with 5e and ""
Then it should get success
Scenario: remove data object Name
Given cmd_put_data with 5b and ""
Then it should get success
Scenario: remove data object Language preference
Given cmd_put_data with 5f2d and ""
Then it should get success
Scenario: remove data object Sex
Given cmd_put_data with 5f35 and ""
Then it should get success
Scenario: remove data object URL
Given cmd_put_data with 5f50 and ""
Then it should get success
Scenario: remove data object pw1 status bytes
Given cmd_put_data with c4 and "\x00"
Then it should get success

View File

@@ -0,0 +1,7 @@
Feature: reset pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: setup PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "admin pass phrase"
Then it should get success

76
test/features/steps.py Normal file
View File

@@ -0,0 +1,76 @@
from freshen import *
from freshen.checks import *
from nose.tools import assert_regexp_matches
import ast
import gnuk
import rsa_keys
@Before
def ini(sc):
if not ftc.token:
ftc.token = gnuk.get_gnuk_device()
ftc.token.cmd_select_openpgp()
@Given("cmd_verify with (.*) and \"(.*)\"")
def cmd_verify(who_str,pass_str):
who = int(who_str)
scc.result = ftc.token.cmd_verify(who, pass_str)
@Given("cmd_change_reference_data with (.*) and \"(.*)\"")
def cmd_change_reference_data(who_str,pass_str):
who = int(who_str)
scc.result = ftc.token.cmd_change_reference_data(who, pass_str)
@Given("cmd_put_data with (.*) and \"(.*)\"")
def cmd_put_data(tag_str,content_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_put_data(tagh, tagl, content_str)
@Given("cmd_reset_retry_counter with (.*) and \"(.*)\"")
def cmd_reset_retry_counter(how_str, data):
how = int(how_str)
scc.result = ftc.token.cmd_reset_retry_counter(how, data)
@Given("a RSA key pair (.*)")
def set_rsa_key(keyno_str):
scc.keyno = int(keyno_str)
@Given("importing it to the token as OPENPGP.(.*)")
def import_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template(openpgp_keyno, scc.keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t)
@When("requesting (.+): ([0-9a-fA-F]+)")
def get_data(name, tag_str):
tag = int(tag_str, 16)
tagh = tag >> 8
tagl = tag & 0xff
scc.result = ftc.token.cmd_get_data(tagh, tagl)
@When("removing a key OPENPGP.(.*)")
def remove_key(openpgp_keyno_str):
openpgp_keyno = int(openpgp_keyno_str)
t = rsa_keys.build_privkey_template_for_remove(openpgp_keyno)
scc.result = ftc.token.cmd_put_data_odd(0x3f, 0xff, t)
@Then("you should get: (.*)")
def check_result(v):
value = ast.literal_eval("'" + v + "'")
assert_equal(scc.result, value)
@Then("it should get success")
def check_success():
assert_equal(scc.result, True)
@Then("you should get NULL")
def check_null():
assert_equal(scc.result, "")
@Then("data should match: (.*)")
def check_regexp(re):
assert_regexp_matches(scc.result, re)

25
test/generate_keys.py Normal file
View File

@@ -0,0 +1,25 @@
from Crypto import Random
from Crypto.PublicKey import RSA
from binascii import hexlify
def print_key_in_hex(k):
prv = k.exportKey(format='DER', pkcs=8)
n = prv[38:38+256]
e = prv[38+256+2:38+256+2+3]
p = prv[38+256+2+3+4+257+4:38+256+2+3+4+257+4+128]
q = prv[38+256+2+3+4+257+4+128+4:38+256+2+3+4+257+4+128+4+128]
n_str = hexlify(n)
e_str = hexlify(e)
p_str = hexlify(p)
q_str = hexlify(q)
if int(p_str, 16)*int(q_str, 16) != int(n_str, 16):
raise ValueError("wrong key", k)
print n_str
print e_str
print p_str
print q_str
rng = Random.new().read
key = RSA.generate(2048, rng)
print_key_in_hex(key)

329
test/gnuk.py Normal file
View File

@@ -0,0 +1,329 @@
"""
gnuk.py - a library for Gnuk Token
This tool is for importing certificate, writing serial number, etc.
Copyright (C) 2011, 2012 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/>.
"""
from struct import *
import string
# Assume only single CCID device is attached to computer, and it's Gnuk Token
import usb
# USB class, subclass, protocol
CCID_CLASS = 0x0B
CCID_SUBCLASS = 0x00
CCID_PROTOCOL_0 = 0x00
def icc_compose(msg_type, data_len, slot, seq, param, data):
return pack('<BiBBBH', msg_type, data_len, slot, seq, 0, param) + data
def iso7816_compose(ins, p1, p2, data, cls=0x00):
data_len = len(data)
if data_len == 0:
return pack('>BBBB', cls, ins, p1, p2)
else:
return pack('>BBBBB', cls, ins, p1, p2, data_len) + data
def list_to_string(l):
return string.join([chr(c) for c in l], '')
class gnuk_token(object):
def __init__(self, device, configuration, interface):
"""
__init__(device, configuration, interface) -> None
Initialize the device.
device: usb.Device object.
configuration: configuration number.
interface: usb.Interface object representing the interface and altenate setting.
"""
if interface.interfaceClass != CCID_CLASS:
raise ValueError("Wrong interface class")
if interface.interfaceSubClass != CCID_SUBCLASS:
raise ValueError("Wrong interface sub class")
self.__devhandle = device.open()
try:
self.__devhandle.setConfiguration(configuration)
except:
pass
self.__devhandle.claimInterface(interface)
self.__devhandle.setAltInterface(interface)
self.__intf = interface.interfaceNumber
self.__alt = interface.alternateSetting
self.__conf = configuration
self.__bulkout = 1
self.__bulkin = 0x81
self.__timeout = 10000
self.__seq = 0
def reset_device(self):
try:
self.__devhandle.reset()
except:
pass
def release_gnuk(self):
self.__devhandle.releaseInterface()
def icc_get_result(self):
msg = self.__devhandle.bulkRead(self.__bulkin, 1024, self.__timeout)
if len(msg) < 10:
print msg
raise ValueError("icc_get_result")
msg_type = msg[0]
data_len = msg[1] + (msg[2]<<8) + (msg[3]<<16) + (msg[4]<<24)
slot = msg[5]
seq = msg[6]
status = msg[7]
error = msg[8]
chain = msg[9]
data = msg[10:]
# XXX: check msg_type, data_len, slot, seq, error
return (status, chain, data)
def icc_get_status(self):
msg = icc_compose(0x65, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_power_on(self):
msg = icc_compose(0x62, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check status, chain
self.atr = list_to_string(data) # ATR
def icc_power_off(self):
msg = icc_compose(0x63, 0, 0, self.__seq, 0, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data = self.icc_get_result()
# XXX: check chain, data
return status
def icc_send_data_block(self, data):
msg = icc_compose(0x6f, len(data), 0, self.__seq, 0, data)
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
return self.icc_get_result()
def icc_send_cmd(self, data):
status, chain, data_rcv = self.icc_send_data_block(data)
if chain == 0:
return data_rcv
elif chain == 1:
d = data_rcv
while True:
msg = icc_compose(0x6f, 0, 0, self.__seq, 0x10, "")
self.__devhandle.bulkWrite(self.__bulkout, msg, self.__timeout)
self.__seq += 1
status, chain, data_rcv = self.icc_get_result()
# XXX: check status
d += data_rcv
if chain == 2:
break
elif chain == 3:
continue
else:
raise ValueError("icc_send_cmd chain")
return d
else:
raise ValueError("icc_send_cmd")
def cmd_get_response(self, expected_len):
result = []
while True:
cmd_data = iso7816_compose(0xc0, 0x00, 0x00, '') + pack('>B', expected_len)
response = self.icc_send_cmd(cmd_data)
result += response[:-2]
sw = response[-2:]
if sw[0] == 0x90 and sw[1] == 0x00:
return list_to_string(result)
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
else:
expected_len = sw[1]
def cmd_verify(self, who, passwd):
cmd_data = iso7816_compose(0x20, 0x00, 0x80+who, passwd)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_read_binary(self, fileid):
cmd_data = iso7816_compose(0xb0, 0x80+fileid, 0x00, '')
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_write_binary(self, fileid, data, is_update):
count = 0
data_len = len(data)
if is_update:
ins = 0xd6
else:
ins = 0xd0
while count*256 < data_len:
if count == 0:
if len(data) < 128:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, 0x80+fileid, 0x00, data[:128], 0x10)
cmd_data1 = iso7816_compose(ins, 0x80+fileid, 0x00, data[128:256])
else:
if len(data[256*count:256*count+128]) < 128:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128])
cmd_data1 = None
else:
cmd_data0 = iso7816_compose(ins, count, 0x00, data[256*count:256*count+128], 0x10)
cmd_data1 = iso7816_compose(ins, count, 0x00, data[256*count+128:256*(count+1)])
sw = self.icc_send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError("cmd_write_binary 0")
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary 0", "%02x%02x" % (sw[0], sw[1]))
if cmd_data1:
sw = self.icc_send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError("cmd_write_binary", sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("cmd_write_binary", "%02x%02x" % (sw[0], sw[1]))
count += 1
def cmd_select_openpgp(self):
cmd_data = iso7816_compose(0xa4, 0x04, 0x0c, "\xD2\x76\x00\x01\x24\x01")
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_get_data(self, tagh, tagl):
cmd_data = iso7816_compose(0xca, tagh, tagl, "")
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError, sw
if sw[0] == 0x90 and sw[1] == 0x00:
return ""
elif sw[0] != 0x61:
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return self.cmd_get_response(sw[1])
def cmd_change_reference_data(self, who, data):
cmd_data = iso7816_compose(0x24, 0x00, 0x80+who, data)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_put_data(self, tagh, tagl, content):
cmd_data = iso7816_compose(0xda, tagh, tagl, content)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_put_data_odd(self, tagh, tagl, content):
cmd_data0 = iso7816_compose(0xdb, tagh, tagl, content[:128], 0x10)
cmd_data1 = iso7816_compose(0xdb, tagh, tagl, content[128:])
sw = self.icc_send_cmd(cmd_data0)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
sw = self.icc_send_cmd(cmd_data1)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def cmd_reset_retry_counter(self, how, data):
cmd_data = iso7816_compose(0x2c, how, 0x00, data)
sw = self.icc_send_cmd(cmd_data)
if len(sw) != 2:
raise ValueError(sw)
if not (sw[0] == 0x90 and sw[1] == 0x00):
raise ValueError("%02x%02x" % (sw[0], sw[1]))
return True
def compare(data_original, data_in_device):
i = 0
for d in data_original:
if ord(d) != data_in_device[i]:
raise ValueError, "verify failed at %08x" % i
i += 1
def gnuk_devices():
busses = usb.busses()
for bus in busses:
devices = bus.devices
for dev in devices:
for config in dev.configurations:
for intf in config.interfaces:
for alt in intf:
if alt.interfaceClass == CCID_CLASS and \
alt.interfaceSubClass == CCID_SUBCLASS and \
alt.interfaceProtocol == CCID_PROTOCOL_0:
yield dev, config, alt
def get_gnuk_device():
icc = None
for (dev, config, intf) in gnuk_devices():
try:
icc = gnuk_token(dev, config, intf)
print "Device: ", dev.filename
print "Configuration: ", config.value
print "Interface: ", intf.interfaceNumber
break
except:
pass
if not icc:
raise ValueError("No ICC present")
status = icc.icc_get_status()
if status == 0:
pass # It's ON already
elif status == 1:
icc.icc_power_on()
else:
raise ValueError("Unknown ICC status", status)
return icc

4
test/rsa-aut.key Normal file
View File

@@ -0,0 +1,4 @@
9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9
010001
b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907
dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf

4
test/rsa-dec.key Normal file
View File

@@ -0,0 +1,4 @@
d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3
010001
dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501
f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3

4
test/rsa-sig.key Normal file
View File

@@ -0,0 +1,4 @@
c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331
010001
cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633
f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b

52
test/rsa_keys.py Normal file
View File

@@ -0,0 +1,52 @@
from binascii import unhexlify
def read_key_from_file(file):
f = open(file)
n_str = f.readline()[:-1]
e_str = f.readline()[:-1]
p_str = f.readline()[:-1]
q_str = f.readline()[:-1]
f.close()
e = int(e_str, 16)
p = int(p_str, 16)
q = int(q_str, 16)
n = int(n_str, 16)
if n != p * q:
raise ValueError("wrong key", p, q, n)
return (unhexlify(n_str), unhexlify(e_str), unhexlify(p_str), unhexlify(q_str))
key = [ None, None, None ]
key[0] = read_key_from_file('rsa-sig.key')
key[1] = read_key_from_file('rsa-dec.key')
key[2] = read_key_from_file('rsa-aut.key')
def build_privkey_template(openpgp_keyno, keyno):
n_str = key[keyno][0]
e_str = '\x00' + key[keyno][1]
p_str = key[keyno][2]
q_str = key[keyno][3]
if openpgp_keyno == 1:
keyspec = '\xb6'
elif openpgp_keyno == 2:
keyspec = '\xb8'
else:
keyspec = '\xa4'
key_template = '\x91\x04'+ '\x92\x81\x80' + '\x93\x81\x80'
exthdr = keyspec + '\x00' + '\x7f\x48' + '\x08' + key_template
suffix = '\x5f\x48' + '\x82\x01\x04'
t = '\x4d' + '\x82\01\16' + exthdr + suffix + e_str + p_str + q_str
return t
def build_privkey_template_for_remove(openpgp_keyno):
if openpgp_keyno == 1:
keyspec = '\xb6'
elif openpgp_keyno == 2:
keyspec = '\xb8'
else:
keyspec = '\xa4'
return '\x4d\02' + keyspec + '\0x00'