From 50700e38877100ff997ebc1e6078d4254555739e Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 12 Oct 2016 10:22:57 +0900 Subject: [PATCH] more tests (incomplete) --- tests/README | 25 +++ tests/card_reader.py | 5 +- tests/conftest.py | 12 ++ tests/openpgp_card.py | 98 ++++++---- tests/rsa-aut.key | 4 + tests/rsa-dec.key | 4 + tests/rsa-sig.key | 4 + tests/rsa_keys.py | 148 +++++++++++++++ tests/test_empty_card.py | 25 +-- tests/test_personalize_card.py | 259 +++++++++++++++++++++++++++ tests/test_personalize_reset_card.py | 86 +++++++++ tests/util.py | 7 + 12 files changed, 619 insertions(+), 58 deletions(-) create mode 100644 tests/rsa-aut.key create mode 100644 tests/rsa-dec.key create mode 100644 tests/rsa-sig.key create mode 100644 tests/rsa_keys.py create mode 100644 tests/test_personalize_card.py create mode 100644 tests/test_personalize_reset_card.py create mode 100644 tests/util.py diff --git a/tests/README b/tests/README index e51c643..204d68c 100644 --- a/tests/README +++ b/tests/README @@ -7,3 +7,28 @@ You need to install: Please run test by typing: $ py.test-3 -x + +test_empty_card.py +000 +001 +002 + +010 +020 +021 +030 +040 +100 +101 +200 +201 +202 +203 +210 +211 +370 +380 +490 + + +003 diff --git a/tests/card_reader.py b/tests/card_reader.py index d3d360f..1e38fb8 100644 --- a/tests/card_reader.py +++ b/tests/card_reader.py @@ -140,6 +140,9 @@ class CardReader(object): except: pass + def is_tpdu_reader(self): + return not self.__use_APDU + def ccid_get_result(self): msg = self.__dev.read(self.__bulkin, 1024, self.__timeout) if len(msg) < 10: @@ -255,7 +258,7 @@ class CardReader(object): return self.ccid_send_cmd(cmd) # TPDU case while len(cmd) > 254: - blk = cmd[0:253] + blk = cmd[0:254] cmd = cmd[254:] while True: self.send_tpdu(info=blk,more=1) diff --git a/tests/conftest.py b/tests/conftest.py index 51aea58..7b85ecf 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,15 @@ +import pytest +from card_reader import get_ccid_device +from openpgp_card import OpenPGP_Card + def pytest_addoption(parser): parser.addoption("--reader", dest="reader", type=str, action="store", default="gnuk", help="specify reader: gnuk or gemalto") + +@pytest.fixture(scope="session") +def card(): + reader = get_ccid_device() + card = OpenPGP_Card(reader) + card.cmd_select_openpgp() + yield card + del card diff --git a/tests/openpgp_card.py b/tests/openpgp_card.py index 5f30d42..84307df 100644 --- a/tests/openpgp_card.py +++ b/tests/openpgp_card.py @@ -32,10 +32,18 @@ def iso7816_compose(ins, p1, p2, data, cls=0x00, le=None): return pack('>BBBBB', cls, ins, p1, p2, le) else: if not le: - return pack('>BBBBB', cls, ins, p1, p2, data_len) + data + if data_len <= 255: + return pack('>BBBBB', cls, ins, p1, p2, data_len) + data + else: + return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \ + + data else: - return pack('>BBBBB', cls, ins, p1, p2, data_len) \ - + data + pack('>B', le) + if data_len <= 255 and le < 256: + return pack('>BBBBB', cls, ins, p1, p2, data_len) \ + + data + pack('>B', le) + else: + return pack('>BBBBBH', cls, ins, p1, p2, 0, data_len) \ + + data + pack('>H', le) class OpenPGP_Card(object): def __init__(self, reader): @@ -156,22 +164,26 @@ class OpenPGP_Card(object): 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.__reader.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.__reader.send_cmd(cmd_data1) + if self.__reader.is_tpdu_reader(): + cmd_data = iso7816_compose(0xdb, tagh, tagl, content) + sw = self.__reader.send_cmd(cmd_data) + else: + cmd_data0 = iso7816_compose(0xdb, tagh, tagl, content[:128], 0x10) + cmd_data1 = iso7816_compose(0xdb, tagh, tagl, content[128:]) + sw = self.__reader.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.__reader.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) + def cmd_reset_retry_counter(self, how, who, data): + cmd_data = iso7816_compose(0x2c, how, who, data) sw = self.__reader.send_cmd(cmd_data) if len(sw) != 2: raise ValueError(sw) @@ -191,30 +203,48 @@ class OpenPGP_Card(object): return self.cmd_get_response(sw[1]) def cmd_pso_longdata(self, p1, p2, data): - cmd_data0 = iso7816_compose(0x2a, p1, p2, data[:128], 0x10) - cmd_data1 = iso7816_compose(0x2a, p1, p2, data[128:]) - sw = self.__reader.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.__reader.send_cmd(cmd_data1) - if len(sw) != 2: - raise ValueError(sw) - elif sw[0] != 0x61: - raise ValueError("%02x%02x" % (sw[0], sw[1])) - return self.cmd_get_response(sw[1]) + if self.__reader.is_tpdu_reader(): + cmd_data = iso7816_compose(0x2a, p1, p2, data, le=256) + print(cmd_data) + r = self.__reader.send_cmd(cmd_data) + if len(r) < 2: + raise ValueError(r) + sw = r[-2:] + r = r[0:-2] + if sw[0] == 0x61: + return self.cmd_get_response(sw[1]) + elif sw[0] == 0x90 and sw[1] == 0x00: + return r + else: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + else: + cmd_data0 = iso7816_compose(0x2a, p1, p2, data[:128], 0x10) + cmd_data1 = iso7816_compose(0x2a, p1, p2, data[128:]) + sw = self.__reader.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.__reader.send_cmd(cmd_data1) + if len(sw) != 2: + raise ValueError(sw) + elif sw[0] != 0x61: + raise ValueError("%02x%02x" % (sw[0], sw[1])) + return self.cmd_get_response(sw[1]) def cmd_internal_authenticate(self, data): - cmd_data = iso7816_compose(0x88, 0, 0, data) - sw = self.__reader.send_cmd(cmd_data) - if len(sw) != 2: - raise ValueError(sw) - if sw[0] == 0x90 and sw[1] == 0x00: - return b"" - elif sw[0] != 0x61: + cmd_data = iso7816_compose(0x88, 0, 0, data, le=256) + r = self.__reader.send_cmd(cmd_data) + if len(r) < 2: + raise ValueError(r) + sw = r[-2:] + r = r[0:-2] + if sw[0] == 0x61: + return self.cmd_get_response(sw[1]) + elif sw[0] == 0x90 and sw[1] == 0x00: + return r + else: raise ValueError("%02x%02x" % (sw[0], sw[1])) - return self.cmd_get_response(sw[1]) def cmd_genkey(self, keyno): if keyno == 1: diff --git a/tests/rsa-aut.key b/tests/rsa-aut.key new file mode 100644 index 0000000..cdf2d5e --- /dev/null +++ b/tests/rsa-aut.key @@ -0,0 +1,4 @@ +9cf7192b51a574d1ad3ccb08ba09b87f228573893eee355529ff243e90fd4b86f79a82097cc7922c0485bed1616b1656a9b0b19ef78ea8ec34c384019adc5d5bf4db2d2a0a2d9cf14277bdcb7056f48b81214e3f7f7742231e29673966f9b1106862112cc798dba8d4a138bb5abfc6d4c12d53a5d39b2f783da916da20852ee139bbafda61d429caf2a4f30847ce7e7ae32ab4061e27dd9e4d00d60910249db8d8559dd85f7ca59659ef400c8f6318700f4e97f0c6f4165de80641490433c88da8682befe68eb311f54af2b07d97ac74edb5399cf054764211694fbb8d1d333f3269f235abe025067f811ff83a2224826219b309ea3e6c968f42b3e52f245dc9 +010001 +b5ab7b159220b18e363258f61ebde08bae83d6ce2dbfe4adc143628c527887acde9de09bf9b49f438019004d71855f30c2d69b6c29bb9882ab641b3387409fe9199464a7faa4b5230c56d9e17cd9ed074bc00180ebed62bae3af28e6ff2ac2654ad968834c5d5c88f8d9d3cc5e167b10453b049d4e454a5761fb0ac717185907 +dd2fffa9814296156a6926cd17b65564187e424dcadce9b032246ad7e46448bb0f9e0ff3c64f987424b1a40bc694e2e9ac4fb1930d163582d7acf20653a1c44b97846c1c5fd8a7b19bb225fb39c30e25410483deaf8c2538d222b748c4d8103b11cec04f666a5c0dbcbf5d5f625f158f65746c3fafe6418145f7cffa5fadeeaf diff --git a/tests/rsa-dec.key b/tests/rsa-dec.key new file mode 100644 index 0000000..8c2aa47 --- /dev/null +++ b/tests/rsa-dec.key @@ -0,0 +1,4 @@ +d392714c29738aac6372f2c8654a08c25a1299fed7004bd512cd2452b503ebad6301130816ac525ba528dc155be6347a5c70407fb4fbdaed751dfc0a7cd5e3910272ff236c4ed1ce5de6620b191a172e5b247347b8cab73a43d79221708755c959a2f83f486439da30917384554331532aabc8326db48866f8c91198834a86ab94679f6175db737bdf399e3f0b737dcb1f4208279d3e1cc694e78686785e4f363a377dec912b7c2f757b1422d866fb9fa85c96b83adfd6a223989a9a02988bdee81ad17eff6385e7b38cec8611fdf367ba4ac8e90d5f48ac7715c5f47aea06a4a37cdaa3029ce59d29bc66853bf6758ef4a7da5a5953f5e557a5a22f67c368c3 +010001 +dae085952c5beee38f25f09bc37a4ca2434c31f78055469d0d5f0bf3337e3a70ba6c91734f195b742e211a5fe283befdf66820008e6ef2c8ca54a91922838fce07d9e33a331ce20dac36803e777d5ee2195ed28d6a4045e28623a6a60b0661e45f7c4f84ae2b1dfad0cf1ec30605158323382a819e730c09a33fad704dd67501 +f774be43ea198aa2f089274e4fffd7d0092ee7b35a1d2f854cdb166f698caab72fdeb099e690e78438b2e043e452d4d2f19d7f44ba6b286642f0ce5204966ff98ecd9e3b448877324631365dc860797429b9414a21a7e166d504cace156588b9a145657eeb1afb43b8ff65d8d6d93cea2ba4ef8aab047885c4de64ffef0b49c3 diff --git a/tests/rsa-sig.key b/tests/rsa-sig.key new file mode 100644 index 0000000..c83179a --- /dev/null +++ b/tests/rsa-sig.key @@ -0,0 +1,4 @@ +c6c877dfd3b441f8fb1b8dc504093a51c2efe4883fe0a6379205acc6e673709905e4d767ddf46143c535cc6d7f10b616f520d8346320ef69ff4a2c4f4a148edc65f7ad24ed7d4fe23bb862a0ae71f4f7904abac0397abf3213df91326b1a25554b3b18cf54584d8bf220169fc92b2aa511e8313983e72b4c9110b3a1aea087aebef95873865608e8faea9ef10e7f7f3a66ca8def2d499c3149c127491e0e4339fd6abe10bfc6c13e43d522004f1485767328eabe35d6ffa8df4c15f0fbcd4eb1c07cc6d85e275139ac69e2962273ae987236926dd6c1144fce3e7ae567fa58ea60620dfafc52f95299fea601739fce27ee71eea978d0074f21e7086f60ba8331 +010001 +cc365b5702714bf203e8c49b0b8afa8dad586e929cf5edca38ad07fa45efd5c2d89022d29f40283a57e50ca24c5f28c8e911a74faaf796f112e7e48195956f9a4df7668a5342523b27179cec958f363211ee11d0ec0e0e1b92ca007a61e8c9ac14e00229b9a7624850199e6667afa1a44db8f3c5de0a8eef0e6de050ac0ac633 +f931a3c12f0e3a5276f712b7706590ba02e14a97ff9b8ce3152af0fc4d9cdc690ea9bc4c82cb16c7d23136cbdab58fbec69880a88bca85c4214df01045082cbe9f4192e3e39c79896533c37dad9eb9e73c2643b9c0a704a4f93d81573537963d6b6e5140a24c702d9f26e06a2095de906daa8824172a6b39f563b7153907050b diff --git a/tests/rsa_keys.py b/tests/rsa_keys.py new file mode 100644 index 0000000..3da4ade --- /dev/null +++ b/tests/rsa_keys.py @@ -0,0 +1,148 @@ +from binascii import hexlify, unhexlify +from time import time +from struct import pack +from hashlib import sha1, sha256 +import string +from os import urandom + +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), e, p, q, n) + +def calc_fpr(n,e): + timestamp = int(time()) + timestamp_data = pack('>I', timestamp) + m_len = 6 + 2 + 256 + 2 + 4 + m = b'\x99' + pack('>H', m_len) + b'\x04' + timestamp_data + b'\x01' + \ + pack('>H', 2048) + n + pack('>H', 17) + e + fpr = sha1(m).digest() + return (fpr, timestamp_data) + +key = [ None, None, None ] +fpr = [ None, None, None ] +timestamp = [ 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') + +(fpr[0], timestamp[0]) = calc_fpr(key[0][0], key[0][1]) +(fpr[1], timestamp[1]) = calc_fpr(key[1][0], key[1][1]) +(fpr[2], timestamp[2]) = calc_fpr(key[2][0], key[2][1]) + +def build_privkey_template(openpgp_keyno, keyno): + n_bytes = key[keyno][0] + e_bytes = b'\x00' + key[keyno][1] + p_bytes = key[keyno][2] + q_bytes = key[keyno][3] + + if openpgp_keyno == 1: + keyspec = b'\xb6' + elif openpgp_keyno == 2: + keyspec = b'\xb8' + else: + keyspec = b'\xa4' + + key_template = b'\x91\x04'+ b'\x92\x81\x80' + b'\x93\x81\x80' + + exthdr = keyspec + b'\x00' + b'\x7f\x48' + b'\x08' + key_template + + suffix = b'\x5f\x48' + b'\x82\x01\x04' + + t = b'\x4d' + b'\x82\x01\x16' + exthdr + suffix + e_bytes + p_bytes + q_bytes + return t + +def build_privkey_template_for_remove(openpgp_keyno): + if openpgp_keyno == 1: + keyspec = b'\xb6' + elif openpgp_keyno == 2: + keyspec = b'\xb8' + else: + keyspec = b'\xa4' + return b'\x4d\02' + keyspec + b'\0x00' + +def compute_digestinfo(msg): + digest = sha256(msg).digest() + prefix = b'\x30\31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20' + return prefix + digest + +# egcd and modinv are from wikibooks +# https://en.wikibooks.org/wiki/Algorithm_Implementation/Mathematics/Extended_Euclidean_algorithm + +def egcd(a, b): + if a == 0: + return (b, 0, 1) + else: + g, y, x = egcd(b % a, a) + return (g, x - (b // a) * y, y) + +def modinv(a, m): + g, x, y = egcd(a, m) + if g != 1: + raise Exception('modular inverse does not exist') + else: + return x % m + +def pkcs1_pad_for_sign(digestinfo): + byte_repr = b'\x00' + b'\x01' + bytes.ljust(b'', 256 - 19 - 32 - 3, b'\xff') \ + + b'\x00' + digestinfo + return int(hexlify(byte_repr), 16) + +def pkcs1_pad_for_crypt(msg): + padlen = 256 - 3 - len(msg) + byte_repr = b'\x00' + b'\x02' \ + + bytes.replace(urandom(padlen), b'\x00', b'\x01') + b'\x00' + msg + return int(hexlify(byte_repr), 16) + +def compute_signature(keyno, digestinfo): + e = key[keyno][4] + p = key[keyno][5] + q = key[keyno][6] + n = key[keyno][7] + p1 = p - 1 + q1 = q - 1 + h = p1 * q1 + d = modinv(e, h) + dp = d % p1 + dq = d % q1 + qp = modinv(q, p) + + input = pkcs1_pad_for_sign(digestinfo) + t1 = pow(input, dp, p) + t2 = pow(input, dq, q) + t = ((t1 - t2) * qp) % p + sig = t2 + t * q + return sig + +def integer_to_bytes_256(i): + return i.to_bytes(256, byteorder='big') + +def encrypt(keyno, plaintext): + e = key[keyno][4] + n = key[keyno][7] + m = pkcs1_pad_for_crypt(plaintext) + return b'\x00' + integer_to_bytes_256(pow(m, e, n)) + +def encrypt_with_pubkey(pubkey_info, plaintext): + n = int(hexlify(pubkey_info[0]), 16) + e = int(hexlify(pubkey_info[1]), 16) + m = pkcs1_pad_for_crypt(plaintext) + return b'\x00' + integer_to_bytes_256(pow(m, e, n)) + +def verify_signature(pubkey_info, digestinfo, sig): + n = int(hexlify(pubkey_info[0]), 16) + e = int(hexlify(pubkey_info[1]), 16) + di_pkcs1 = pow(sig,e,n) + m = pkcs1_pad_for_sign(digestinfo) + return di_pkcs1 == m diff --git a/tests/test_empty_card.py b/tests/test_empty_card.py index c7774f7..a9fd615 100644 --- a/tests/test_empty_card.py +++ b/tests/test_empty_card.py @@ -1,5 +1,5 @@ """ -test_empty_card.py - testing empty card +test_empty_card.py - test empty card Copyright (C) 2016 g10 Code GmbH Author: NIIBE Yutaka @@ -20,35 +20,14 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -import pytest from re import match, DOTALL +from util import * EMPTY_60=bytes(60) FACTORY_PASSPHRASE_PW1=b"123456" FACTORY_PASSPHRASE_PW3=b"12345678" -@pytest.fixture(scope="module") -def card(): - if pytest.config.option.reader == "gnuk": - from card_reader import get_ccid_device - reader = get_ccid_device() - from openpgp_card import OpenPGP_Card - card = OpenPGP_Card(reader) - else: - raise ValueError("Reader Not Supported") - card.cmd_select_openpgp() - yield card - del card - -def get_data_object(card, tag): - tagh = tag >> 8 - tagl = tag & 0xff - return card.cmd_get_data(tagh, tagl) - -def check_null(data_object): - return data_object == None or len(data_object) == 0 - def test_login(card): login = get_data_object(card, 0x5e) assert check_null(login) diff --git a/tests/test_personalize_card.py b/tests/test_personalize_card.py new file mode 100644 index 0000000..0a76199 --- /dev/null +++ b/tests/test_personalize_card.py @@ -0,0 +1,259 @@ +""" +test_personalize_card.py - test personalizing card + +Copyright (C) 2016 g10 Code GmbH +Author: NIIBE Yutaka + +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 . +""" + +from struct import pack +from re import match, DOTALL +from util import * +import rsa_keys + +FACTORY_PASSPHRASE_PW1=b"123456" +FACTORY_PASSPHRASE_PW3=b"12345678" +PW1_TEST0=b"another user pass phrase" +PW1_TEST1=b"PASSPHRASE SHOULD BE LONG" +PW1_TEST2=b"new user pass phrase" +PW1_TEST3=b"next user pass phrase" +PW1_TEST4=b"another user pass phrase" +PW3_TEST0=b"admin pass phrase" +PW3_TEST1=b"another admin pass phrase" + +RESETCODE_TEST=b"example reset code 000" + +def test_setup_pw3_0(card): + r = card.cmd_change_reference_data(3, FACTORY_PASSPHRASE_PW3 + PW3_TEST0) + assert r + +def test_verify_pw3_0(card): + v = card.cmd_verify(3, PW3_TEST0) + assert v + +def test_login_put(card): + r = card.cmd_put_data(0x00, 0x5e, b"gpg_user") + assert r + +def test_name_put(card): + r = card.cmd_put_data(0x00, 0x5b, b"GnuPG User") + assert r + +def test_lang_put(card): + r = card.cmd_put_data(0x5f, 0x2d, b"ja") + assert r + +def test_sex_put(card): + r = card.cmd_put_data(0x5f, 0x35, b"1") + assert r + +def test_url_put(card): + r = card.cmd_put_data(0x5f, 0x50, b"https://www.fsij.org/gnuk/") + assert r + +def test_pw1_status_put(card): + r = card.cmd_put_data(0x00, 0xc4, b"\x01") + assert r + +def test_login(card): + login = get_data_object(card, 0x5e) + assert login == b"gpg_user" + +def test_name_lang_sex(card): + name = b"GnuPG User" + lang = b"ja" + sex = b"1" + expected = b'\x5b' + pack('B', len(name)) + name \ + + b'\x5f\x2d' + pack('B', len(lang)) + lang \ + + b'\x5f\x35' + pack('B', len(sex)) + sex + name_lang_sex = get_data_object(card, 0x65) + assert name_lang_sex == expected + +def test_url(card): + url = get_data_object(card, 0x5f50) + assert url == b"https://www.fsij.org/gnuk/" + +def test_pw1_status(card): + s = get_data_object(card, 0xc4) + assert match(b'\x01...\x03[\x00\x03]\x03', s, DOTALL) + +def test_rsa_import_key_1(card): + t = rsa_keys.build_privkey_template(1, 0) + r = card.cmd_put_data_odd(0x3f, 0xff, t) + assert r + +def test_rsa_import_key_2(card): + t = rsa_keys.build_privkey_template(2, 1) + r = card.cmd_put_data_odd(0x3f, 0xff, t) + assert r + +def test_rsa_import_key_3(card): + t = rsa_keys.build_privkey_template(3, 2) + r = card.cmd_put_data_odd(0x3f, 0xff, t) + assert r + +def test_fingerprint_1_put(card): + fpr1 = rsa_keys.fpr[0] + r = card.cmd_put_data(0x00, 0xc7, fpr1) + assert r + +def test_fingerprint_2_put(card): + fpr2 = rsa_keys.fpr[1] + r = card.cmd_put_data(0x00, 0xc8, fpr2) + assert r + +def test_fingerprint_3_put(card): + fpr3 = rsa_keys.fpr[2] + r = card.cmd_put_data(0x00, 0xc9, fpr3) + assert r + +def test_timestamp_1(card): + timestamp1 = rsa_keys.timestamp[0] + r = card.cmd_put_data(0x00, 0xce, timestamp1) + assert r + +def test_timestamp_2(card): + timestamp2 = rsa_keys.timestamp[1] + r = card.cmd_put_data(0x00, 0xcf, timestamp2) + assert r + +def test_timestamp_3(card): + timestamp3 = rsa_keys.timestamp[2] + r = card.cmd_put_data(0x00, 0xd0, timestamp3) + assert r + +def test_setup_pw1_0(card): + r = card.cmd_change_reference_data(1, FACTORY_PASSPHRASE_PW1 + PW1_TEST0) + assert r + +def test_verify_pw1_0(card): + v = card.cmd_verify(1, PW1_TEST0) + assert v + +def test_verify_pw1_0_2(card): + v = card.cmd_verify(2, PW1_TEST0) + assert v + +def test_setup_pw1_1(card): + r = card.cmd_change_reference_data(1, PW1_TEST0 + PW1_TEST1) + assert r + +def test_verify_pw1_1(card): + v = card.cmd_verify(1, PW1_TEST1) + assert v + +def test_verify_pw1_1_2(card): + v = card.cmd_verify(2, PW1_TEST1) + assert v + +def test_setup_reset_code(card): + r = card.cmd_put_data(0x00, 0xd3, RESETCODE_TEST) + assert r + +def test_reset_code(card): + r = card.cmd_reset_retry_counter(0, 0x81, RESETCODE_TEST + PW1_TEST2) + assert r + +def test_verify_pw1_2(card): + v = card.cmd_verify(1, PW1_TEST2) + assert v + +def test_verify_pw1_2_2(card): + v = card.cmd_verify(2, PW1_TEST2) + assert v + +def test_setup_pw3_1(card): + r = card.cmd_change_reference_data(3, PW3_TEST0 + PW3_TEST1) + assert r + +def test_verify_pw3_1(card): + v = card.cmd_verify(3, PW3_TEST1) + assert v + +def test_reset_userpass_admin(card): + r = card.cmd_reset_retry_counter(2, 0x81, PW1_TEST3) + assert r + +def test_verify_pw1_3(card): + v = card.cmd_verify(1, PW1_TEST3) + assert v + +def test_verify_pw1_3_2(card): + v = card.cmd_verify(2, PW1_TEST3) + assert v + +def test_setup_pw1_4(card): + r = card.cmd_change_reference_data(1, PW1_TEST3 + PW1_TEST4) + assert r + +def test_verify_pw1_4(card): + v = card.cmd_verify(1, PW1_TEST4) + assert v + +def test_verify_pw1_4_2(card): + v = card.cmd_verify(2, PW1_TEST4) + assert v + +def test_setup_pw3_2(card): + r = card.cmd_change_reference_data(3, PW3_TEST1 + PW3_TEST0) + assert r + +def test_verify_pw3_2(card): + v = card.cmd_verify(3, PW3_TEST0) + assert v + +PLAIN_TEXT0=b"This is a test message." +PLAIN_TEXT1=b"RSA decryption is as easy as pie." +PLAIN_TEXT2=b"This is another test message.\nMultiple lines.\n" + +def test_sign_0(card): + digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0) + r = card.cmd_pso_longdata(0x9e, 0x9a, digestinfo) + sig = rsa_keys.compute_signature(0, digestinfo) + sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big') + assert r == sig_bytes + +def test_sign_1(card): + digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1) + r = card.cmd_pso_longdata(0x9e, 0x9a, digestinfo) + sig = rsa_keys.compute_signature(0, digestinfo) + sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big') + assert r == sig_bytes + +def test_sign_auth_0(card): + digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT0) + r = card.cmd_internal_authenticate(digestinfo) + sig = rsa_keys.compute_signature(2, digestinfo) + sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big') + assert r == sig_bytes + +def test_sign_auth_1(card): + digestinfo = rsa_keys.compute_digestinfo(PLAIN_TEXT1) + r = card.cmd_internal_authenticate(digestinfo) + sig = rsa_keys.compute_signature(2, digestinfo) + sig_bytes = sig.to_bytes(int((sig.bit_length()+7)/8), byteorder='big') + assert r == sig_bytes + +def test_decrypt_0(card): + ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT0) + r = card.cmd_pso_longdata(0x80, 0x86, ciphertext) + assert r == PLAIN_TEXT0 + +def test_decrypt_1(card): + ciphertext = rsa_keys.encrypt(1, PLAIN_TEXT1) + r = card.cmd_pso_longdata(0x80, 0x86, ciphertext) + assert r == PLAIN_TEXT1 diff --git a/tests/test_personalize_reset_card.py b/tests/test_personalize_reset_card.py new file mode 100644 index 0000000..bc5c986 --- /dev/null +++ b/tests/test_personalize_reset_card.py @@ -0,0 +1,86 @@ +""" +test_personalize_reset_card.py - test resetting personalization of card + +Copyright (C) 2016 g10 Code GmbH +Author: NIIBE Yutaka + +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 . +""" + +from struct import pack +from re import match, DOTALL +from util import * +import rsa_keys + +FACTORY_PASSPHRASE_PW1=b"123456" +FACTORY_PASSPHRASE_PW3=b"12345678" +PW1_TEST0=b"another user pass phrase" +PW1_TEST1=b"PASSPHRASE SHOULD BE LONG" +PW1_TEST2=b"new user pass phrase" +PW1_TEST3=b"next user pass phrase" +PW1_TEST4=b"another user pass phrase" +PW3_TEST0=b"admin pass phrase" +PW3_TEST1=b"another admin pass phrase" + +RESETCODE_TEST=b"example reset code 000" + +def test_login_put(card): + r = card.cmd_put_data(0x00, 0x5e, b"") + assert r + +def test_name_put(card): + r = card.cmd_put_data(0x00, 0x5b, b"") + assert r + +def test_lang_put(card): + r = card.cmd_put_data(0x5f, 0x2d, b"de") + assert r + +def test_sex_put(card): + r = card.cmd_put_data(0x5f, 0x35, b"0") + assert r + +def test_url_put(card): + r = card.cmd_put_data(0x5f, 0x50, b"") + assert r + +def test_pw1_status_put(card): + r = card.cmd_put_data(0x00, 0xc4, b"\x00") + assert r + +def test_setup_pw3_0(card): + r = card.cmd_change_reference_data(3, PW3_TEST0 + FACTORY_PASSPHRASE_PW3) + assert r + +def test_verify_pw3_0(card): + v = card.cmd_verify(3, FACTORY_PASSPHRASE_PW3) + assert v + +def test_setup_pw1_0(card): + r = card.cmd_change_reference_data(1, PW1_TEST4 + FACTORY_PASSPHRASE_PW1) + assert r + +def test_verify_pw1_0(card): + v = card.cmd_verify(1, FACTORY_PASSPHRASE_PW1) + assert v + +def test_verify_pw1_0_2(card): + v = card.cmd_verify(2, FACTORY_PASSPHRASE_PW1) + assert v + +def test_setup_reset_code(card): + r = card.cmd_put_data(0x00, 0xd3, b"") + assert r diff --git a/tests/util.py b/tests/util.py new file mode 100644 index 0000000..9e2726a --- /dev/null +++ b/tests/util.py @@ -0,0 +1,7 @@ +def get_data_object(card, tag): + tagh = tag >> 8 + tagl = tag & 0xff + return card.cmd_get_data(tagh, tagl) + +def check_null(data_object): + return data_object == None or len(data_object) == 0