From dcef6e0ffa6bdd5013e9d5e05fd842c9064af5d5 Mon Sep 17 00:00:00 2001 From: Vincent Pelletier Date: Mon, 1 Mar 2021 23:04:28 +0000 Subject: [PATCH] tests/card_test_personalize_card.py: Exercise ECDH, X25519 and ED25519. ECDH curves exercised are OpenPGP recommended set: ANSIx9p{256,384,521}r1 and BRAINPOOLp{256,384,512}r1, plus X25519 and ED25519. Signature is only tested (for now ?) with ED25519 as other signature schemes are (usually) non-deterministic and require implementing the signature verification algorithm rather than just testing for equality with a test vector. Signed-off-by: Vincent Pelletier --- tests/card_const.py | 8 +++ tests/card_test_ansix9p256r1.py | 58 ++++++++++++++++ tests/card_test_ansix9p384r1.py | 64 +++++++++++++++++ tests/card_test_ansix9p512r1.py | 76 ++++++++++++++++++++ tests/card_test_brainpoolp256r1.py | 58 ++++++++++++++++ tests/card_test_brainpoolp384r1.py | 64 +++++++++++++++++ tests/card_test_brainpoolp512r1.py | 70 +++++++++++++++++++ tests/card_test_ed25519.py | 51 ++++++++++++++ tests/card_test_x25519.py | 52 ++++++++++++++ tests/func_pso_auth.py | 108 +++++++++++++++++++++++++++++ tests/test_006_pso.py | 8 +++ 11 files changed, 617 insertions(+) create mode 100644 tests/card_test_ansix9p256r1.py create mode 100644 tests/card_test_ansix9p384r1.py create mode 100644 tests/card_test_ansix9p512r1.py create mode 100644 tests/card_test_brainpoolp256r1.py create mode 100644 tests/card_test_brainpoolp384r1.py create mode 100644 tests/card_test_brainpoolp512r1.py create mode 100644 tests/card_test_ed25519.py create mode 100644 tests/card_test_x25519.py create mode 100644 tests/func_pso_auth.py create mode 100644 tests/test_006_pso.py diff --git a/tests/card_const.py b/tests/card_const.py index 2f9aeb2..b091305 100644 --- a/tests/card_const.py +++ b/tests/card_const.py @@ -2,3 +2,11 @@ FACTORY_PASSPHRASE_PW1=b"123456" FACTORY_PASSPHRASE_PW3=b"12345678" KEY_ATTRIBUTES_RSA4K=b"\x01\x10\x00\x00\x20\x00" KEY_ATTRIBUTES_RSA2K=b"\x01\x08\x00\x00\x20\x00" +KEY_ATTRIBUTES_ECDH_ANSIX9P256R1=b"\x12\x2a\x86\x48\xce\x3d\x03\x01\x07" +KEY_ATTRIBUTES_ECDH_ANSIX9P384R1=b"\x12\x2b\x81\x04\x00\x22" +KEY_ATTRIBUTES_ECDH_ANSIX9P521R1=b"\x12\x2b\x81\x04\x00\x23" +KEY_ATTRIBUTES_ECDH_BRAINPOOLP256R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x07" +KEY_ATTRIBUTES_ECDH_BRAINPOOLP384R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x0b" +KEY_ATTRIBUTES_ECDH_BRAINPOOLP512R1=b"\x12\x2b\x24\x03\x03\x02\x08\x01\x01\x0d" +KEY_ATTRIBUTES_X25519=b"\x12\x2b\x06\x01\x04\x01\x97\x55\x01\x05\x01" +KEY_ATTRIBUTES_ED25519=b"\x16\x2b\x06\x01\x04\x01\xda\x47\x0f\x01" diff --git a/tests/card_test_ansix9p256r1.py b/tests/card_test_ansix9p256r1.py new file mode 100644 index 0000000..5844a8a --- /dev/null +++ b/tests/card_test_ansix9p256r1.py @@ -0,0 +1,58 @@ +""" +card_test_ansix9p256r1.py - test ansix9p256r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_AnsiX9P256R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc5903#section-8.1 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P256R1, + key_attribute_caption='ECDH ansix9p256r1', + private_key=( + b'\xC8\x8F\x01\xF5\x10\xD9\xAC\x3F\x70\xA2\x92\xDA\xA2\x31\x6D\xE5' + b'\x44\xE9\xAA\xB8\xAF\xE8\x40\x49\xC6\x2A\x9C\x57\x86\x2D\x14\x33' + ), + expected_public_key=( + b'\x04' + b'\xDA\xD0\xB6\x53\x94\x22\x1C\xF9\xB0\x51\xE1\xFE\xCA\x57\x87\xD0' + b'\x98\xDF\xE6\x37\xFC\x90\xB9\xEF\x94\x5D\x0C\x37\x72\x58\x11\x80' + b'\x52\x71\xA0\x46\x1C\xDB\x82\x52\xD6\x1F\x1C\x45\x6F\xA3\xE5\x9A' + b'\xB1\xF4\x5B\x33\xAC\xCF\x5F\x58\x38\x9E\x05\x77\xB8\x99\x0B\xB3' + ), + pso_input=( + b'\xa6\x46\x7f\x49\x43\x86\x41' + b'\x04' + b'\xD1\x2D\xFB\x52\x89\xC8\xD4\xF8\x12\x08\xB7\x02\x70\x39\x8C\x34' + b'\x22\x96\x97\x0A\x0B\xCC\xB7\x4C\x73\x6F\xC7\x55\x44\x94\xBF\x63' + b'\x56\xFB\xF3\xCA\x36\x6C\xC2\x3E\x81\x57\x85\x4C\x13\xC5\x8D\x6A' + b'\xAC\x23\xF0\x46\xAD\xA3\x0F\x83\x53\xE7\x4F\x33\x03\x98\x72\xAB' + ), + expected_pso_output=( + b'\xD6\x84\x0F\x6B\x42\xF6\xED\xAF\xD1\x31\x16\xE0\xE1\x25\x65\x20' + b'\x2F\xEF\x8E\x9E\xCE\x7D\xCE\x03\x81\x24\x64\xD0\x4B\x94\x42\xDE' + ), + ) diff --git a/tests/card_test_ansix9p384r1.py b/tests/card_test_ansix9p384r1.py new file mode 100644 index 0000000..4619d3b --- /dev/null +++ b/tests/card_test_ansix9p384r1.py @@ -0,0 +1,64 @@ +""" +card_test_ansix9p384r1.py - test ansix9p384r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_AnsiX9P384R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc5903#section-8.2 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P384R1, + key_attribute_caption='ECDH ansix9p384r1', + private_key=( + b'\x09\x9F\x3C\x70\x34\xD4\xA2\xC6\x99\x88\x4D\x73\xA3\x75\xA6\x7F' + b'\x76\x24\xEF\x7C\x6B\x3C\x0F\x16\x06\x47\xB6\x74\x14\xDC\xE6\x55' + b'\xE3\x5B\x53\x80\x41\xE6\x49\xEE\x3F\xAE\xF8\x96\x78\x3A\xB1\x94' + ), + expected_public_key=( + b'\x04' + b'\x66\x78\x42\xD7\xD1\x80\xAC\x2C\xDE\x6F\x74\xF3\x75\x51\xF5\x57' + b'\x55\xC7\x64\x5C\x20\xEF\x73\xE3\x16\x34\xFE\x72\xB4\xC5\x5E\xE6' + b'\xDE\x3A\xC8\x08\xAC\xB4\xBD\xB4\xC8\x87\x32\xAE\xE9\x5F\x41\xAA' + b'\x94\x82\xED\x1F\xC0\xEE\xB9\xCA\xFC\x49\x84\x62\x5C\xCF\xC2\x3F' + b'\x65\x03\x21\x49\xE0\xE1\x44\xAD\xA0\x24\x18\x15\x35\xA0\xF3\x8E' + b'\xEB\x9F\xCF\xF3\xC2\xC9\x47\xDA\xE6\x9B\x4C\x63\x45\x73\xA8\x1C' + ), + pso_input=( + b'\xa6\x66\x7f\x49\x63\x86\x61' + b'\x04' + b'\xE5\x58\xDB\xEF\x53\xEE\xCD\xE3\xD3\xFC\xCF\xC1\xAE\xA0\x8A\x89' + b'\xA9\x87\x47\x5D\x12\xFD\x95\x0D\x83\xCF\xA4\x17\x32\xBC\x50\x9D' + b'\x0D\x1A\xC4\x3A\x03\x36\xDE\xF9\x6F\xDA\x41\xD0\x77\x4A\x35\x71' + b'\xDC\xFB\xEC\x7A\xAC\xF3\x19\x64\x72\x16\x9E\x83\x84\x30\x36\x7F' + b'\x66\xEE\xBE\x3C\x6E\x70\xC4\x16\xDD\x5F\x0C\x68\x75\x9D\xD1\xFF' + b'\xF8\x3F\xA4\x01\x42\x20\x9D\xFF\x5E\xAA\xD9\x6D\xB9\xE6\x38\x6C' + ), + expected_pso_output=( + b'\x11\x18\x73\x31\xC2\x79\x96\x2D\x93\xD6\x04\x24\x3F\xD5\x92\xCB' + b'\x9D\x0A\x92\x6F\x42\x2E\x47\x18\x75\x21\x28\x7E\x71\x56\xC5\xC4' + b'\xD6\x03\x13\x55\x69\xB9\xE9\xD0\x9C\xF5\xD4\xA2\x70\xF5\x97\x46' + ), + ) diff --git a/tests/card_test_ansix9p512r1.py b/tests/card_test_ansix9p512r1.py new file mode 100644 index 0000000..66c18d4 --- /dev/null +++ b/tests/card_test_ansix9p512r1.py @@ -0,0 +1,76 @@ +""" +card_test_ansix9p512r1.py - test ansix9p512r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_AnsiX9P512R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc5903#section-8.3 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_ANSIX9P521R1, + key_attribute_caption='ECDH ansix9p521r1', + private_key=( + b'\x00\x37\xAD\xE9\x31\x9A\x89\xF4\xDA\xBD\xB3\xEF\x41\x1A\xAC\xCC' + b'\xA5\x12\x3C\x61\xAC\xAB\x57\xB5\x39\x3D\xCE\x47\x60\x81\x72\xA0' + b'\x95\xAA\x85\xA3\x0F\xE1\xC2\x95\x2C\x67\x71\xD9\x37\xBA\x97\x77' + b'\xF5\x95\x7B\x26\x39\xBA\xB0\x72\x46\x2F\x68\xC2\x7A\x57\x38\x2D' + b'\x4A\x52' + ), + expected_public_key=( + b'\x04' + b'\x00\x15\x41\x7E\x84\xDB\xF2\x8C\x0A\xD3\xC2\x78\x71\x33\x49\xDC' + b'\x7D\xF1\x53\xC8\x97\xA1\x89\x1B\xD9\x8B\xAB\x43\x57\xC9\xEC\xBE' + b'\xE1\xE3\xBF\x42\xE0\x0B\x8E\x38\x0A\xEA\xE5\x7C\x2D\x10\x75\x64' + b'\x94\x18\x85\x94\x2A\xF5\xA7\xF4\x60\x17\x23\xC4\x19\x5D\x17\x6C' + b'\xED\x3E' + b'\x01\x7C\xAE\x20\xB6\x64\x1D\x2E\xEB\x69\x57\x86\xD8\xC9\x46\x14' + b'\x62\x39\xD0\x99\xE1\x8E\x1D\x5A\x51\x4C\x73\x9D\x7C\xB4\xA1\x0A' + b'\xD8\xA7\x88\x01\x5A\xC4\x05\xD7\x79\x9D\xC7\x5E\x7B\x7D\x5B\x6C' + b'\xF2\x26\x1A\x6A\x7F\x15\x07\x43\x8B\xF0\x1B\xEB\x6C\xA3\x92\x6F' + b'\x95\x82' + ), + pso_input=( + b'\xa6\x81\x8c\x7f\x49\x81\x88\x86\x81\x85' + b'\x04' + b'\x00\xD0\xB3\x97\x5A\xC4\xB7\x99\xF5\xBE\xA1\x6D\x5E\x13\xE9\xAF' + b'\x97\x1D\x5E\x9B\x98\x4C\x9F\x39\x72\x8B\x5E\x57\x39\x73\x5A\x21' + b'\x9B\x97\xC3\x56\x43\x6A\xDC\x6E\x95\xBB\x03\x52\xF6\xBE\x64\xA6' + b'\xC2\x91\x2D\x4E\xF2\xD0\x43\x3C\xED\x2B\x61\x71\x64\x00\x12\xD9' + b'\x46\x0F' + b'\x01\x5C\x68\x22\x63\x83\x95\x6E\x3B\xD0\x66\xE7\x97\xB6\x23\xC2' + b'\x7C\xE0\xEA\xC2\xF5\x51\xA1\x0C\x2C\x72\x4D\x98\x52\x07\x7B\x87' + b'\x22\x0B\x65\x36\xC5\xC4\x08\xA1\xD2\xAE\xBB\x8E\x86\xD6\x78\xAE' + b'\x49\xCB\x57\x09\x1F\x47\x32\x29\x65\x79\xAB\x44\xFC\xD1\x7F\x0F' + b'\xC5\x6A' + ), + expected_pso_output=( + b'\x01\x14\x4C\x7D\x79\xAE\x69\x56\xBC\x8E\xDB\x8E\x7C\x78\x7C\x45' + b'\x21\xCB\x08\x6F\xA6\x44\x07\xF9\x78\x94\xE5\xE6\xB2\xD7\x9B\x04' + b'\xD1\x42\x7E\x73\xCA\x4B\xAA\x24\x0A\x34\x78\x68\x59\x81\x0C\x06' + b'\xB3\xC7\x15\xA3\xA8\xCC\x31\x51\xF2\xBE\xE4\x17\x99\x6D\x19\xF3' + b'\xDD\xEA' + ), + ) diff --git a/tests/card_test_brainpoolp256r1.py b/tests/card_test_brainpoolp256r1.py new file mode 100644 index 0000000..bc48c9b --- /dev/null +++ b/tests/card_test_brainpoolp256r1.py @@ -0,0 +1,58 @@ +""" +card_test_brainpoolp256r1.py - test brainpoolp256r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_BrainpoolP256R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc7027#appendix-A.1 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP256R1, + key_attribute_caption='ECDH brainpoolp256r1', + private_key=( + b'\x81\xDB\x1E\xE1\x00\x15\x0F\xF2\xEA\x33\x8D\x70\x82\x71\xBE\x38' + b'\x30\x0C\xB5\x42\x41\xD7\x99\x50\xF7\x7B\x06\x30\x39\x80\x4F\x1D' + ), + expected_public_key=( + b'\x04' + b'\x44\x10\x6E\x91\x3F\x92\xBC\x02\xA1\x70\x5D\x99\x53\xA8\x41\x4D' + b'\xB9\x5E\x1A\xAA\x49\xE8\x1D\x9E\x85\xF9\x29\xA8\xE3\x10\x0B\xE5' + b'\x8A\xB4\x84\x6F\x11\xCA\xCC\xB7\x3C\xE4\x9C\xBD\xD1\x20\xF5\xA9' + b'\x00\xA6\x9F\xD3\x2C\x27\x22\x23\xF7\x89\xEF\x10\xEB\x08\x9B\xDC' + ), + pso_input=( + b'\xa6\x46\x7f\x49\x43\x86\x41' + b'\x04' + b'\x8D\x2D\x68\x8C\x6C\xF9\x3E\x11\x60\xAD\x04\xCC\x44\x29\x11\x7D' + b'\xC2\xC4\x18\x25\xE1\xE9\xFC\xA0\xAD\xDD\x34\xE6\xF1\xB3\x9F\x7B' + b'\x99\x0C\x57\x52\x08\x12\xBE\x51\x26\x41\xE4\x70\x34\x83\x21\x06' + b'\xBC\x7D\x3E\x8D\xD0\xE4\xC7\xF1\x13\x6D\x70\x06\x54\x7C\xEC\x6A' + ), + expected_pso_output=( + b'\x89\xAF\xC3\x9D\x41\xD3\xB3\x27\x81\x4B\x80\x94\x0B\x04\x25\x90' + b'\xF9\x65\x56\xEC\x91\xE6\xAE\x79\x39\xBC\xE3\x1F\x3A\x18\xBF\x2B' + ), + ) diff --git a/tests/card_test_brainpoolp384r1.py b/tests/card_test_brainpoolp384r1.py new file mode 100644 index 0000000..d8760aa --- /dev/null +++ b/tests/card_test_brainpoolp384r1.py @@ -0,0 +1,64 @@ +""" +card_test_brainpoolp384r1.py - test brainpoolp384r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_BrainpoolP384R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc7027#appendix-A.2 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP384R1, + key_attribute_caption='ECDH brainpoolp384r1', + private_key=( + b'\x1E\x20\xF5\xE0\x48\xA5\x88\x6F\x1F\x15\x7C\x74\xE9\x1B\xDE\x2B' + b'\x98\xC8\xB5\x2D\x58\xE5\x00\x3D\x57\x05\x3F\xC4\xB0\xBD\x65\xD6' + b'\xF1\x5E\xB5\xD1\xEE\x16\x10\xDF\x87\x07\x95\x14\x36\x27\xD0\x42' + ), + expected_public_key=( + b'\x04' + b'\x68\xB6\x65\xDD\x91\xC1\x95\x80\x06\x50\xCD\xD3\x63\xC6\x25\xF4' + b'\xE7\x42\xE8\x13\x46\x67\xB7\x67\xB1\xB4\x76\x79\x35\x88\xF8\x85' + b'\xAB\x69\x8C\x85\x2D\x4A\x6E\x77\xA2\x52\xD6\x38\x0F\xCA\xF0\x68' + b'\x55\xBC\x91\xA3\x9C\x9E\xC0\x1D\xEE\x36\x01\x7B\x7D\x67\x3A\x93' + b'\x12\x36\xD2\xF1\xF5\xC8\x39\x42\xD0\x49\xE3\xFA\x20\x60\x74\x93' + b'\xE0\xD0\x38\xFF\x2F\xD3\x0C\x2A\xB6\x7D\x15\xC8\x5F\x7F\xAA\x59' + ), + pso_input=( + b'\xa6\x66\x7f\x49\x63\x86\x61' + b'\x04' + b'\x4D\x44\x32\x6F\x26\x9A\x59\x7A\x5B\x58\xBB\xA5\x65\xDA\x55\x56' + b'\xED\x7F\xD9\xA8\xA9\xEB\x76\xC2\x5F\x46\xDB\x69\xD1\x9D\xC8\xCE' + b'\x6A\xD1\x8E\x40\x4B\x15\x73\x8B\x20\x86\xDF\x37\xE7\x1D\x1E\xB4' + b'\x62\xD6\x92\x13\x6D\xE5\x6C\xBE\x93\xBF\x5F\xA3\x18\x8E\xF5\x8B' + b'\xC8\xA3\xA0\xEC\x6C\x1E\x15\x1A\x21\x03\x8A\x42\xE9\x18\x53\x29' + b'\xB5\xB2\x75\x90\x3D\x19\x2F\x8D\x4E\x1F\x32\xFE\x9C\xC7\x8C\x48' + ), + expected_pso_output=( + b'\x0B\xD9\xD3\xA7\xEA\x0B\x3D\x51\x9D\x09\xD8\xE4\x8D\x07\x85\xFB' + b'\x74\x4A\x6B\x35\x5E\x63\x04\xBC\x51\xC2\x29\xFB\xBC\xE2\x39\xBB' + b'\xAD\xF6\x40\x37\x15\xC3\x5D\x4F\xB2\xA5\x44\x4F\x57\x5D\x4F\x42' + ), + ) diff --git a/tests/card_test_brainpoolp512r1.py b/tests/card_test_brainpoolp512r1.py new file mode 100644 index 0000000..9c422f2 --- /dev/null +++ b/tests/card_test_brainpoolp512r1.py @@ -0,0 +1,70 @@ +""" +card_test_brainpoolp512r1.py - test brainpoolp512r1 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_BrainpoolP512R1(object): + def test_ECDH_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc7027#appendix-A.3 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_ECDH_BRAINPOOLP512R1, + key_attribute_caption='ECDH brainpoolp512r1', + private_key=( + b'\x16\x30\x2F\xF0\xDB\xBB\x5A\x8D\x73\x3D\xAB\x71\x41\xC1\xB4\x5A' + b'\xCB\xC8\x71\x59\x39\x67\x7F\x6A\x56\x85\x0A\x38\xBD\x87\xBD\x59' + b'\xB0\x9E\x80\x27\x96\x09\xFF\x33\x3E\xB9\xD4\xC0\x61\x23\x1F\xB2' + b'\x6F\x92\xEE\xB0\x49\x82\xA5\xF1\xD1\x76\x4C\xAD\x57\x66\x54\x22' + ), + expected_public_key=( + b'\x04' + b'\x0A\x42\x05\x17\xE4\x06\xAA\xC0\xAC\xDC\xE9\x0F\xCD\x71\x48\x77' + b'\x18\xD3\xB9\x53\xEF\xD7\xFB\xEC\x5F\x7F\x27\xE2\x8C\x61\x49\x99' + b'\x93\x97\xE9\x1E\x02\x9E\x06\x45\x7D\xB2\xD3\xE6\x40\x66\x8B\x39' + b'\x2C\x2A\x7E\x73\x7A\x7F\x0B\xF0\x44\x36\xD1\x16\x40\xFD\x09\xFD' + b'\x72\xE6\x88\x2E\x8D\xB2\x8A\xAD\x36\x23\x7C\xD2\x5D\x58\x0D\xB2' + b'\x37\x83\x96\x1C\x8D\xC5\x2D\xFA\x2E\xC1\x38\xAD\x47\x2A\x0F\xCE' + b'\xF3\x88\x7C\xF6\x2B\x62\x3B\x2A\x87\xDE\x5C\x58\x83\x01\xEA\x3E' + b'\x5F\xC2\x69\xB3\x73\xB6\x07\x24\xF5\xE8\x2A\x6A\xD1\x47\xFD\xE7' + ), + pso_input=( + b'\xa6\x81\x88\x7f\x49\x81\x84\x86\x81\x81' + b'\x04' + b'\x9D\x45\xF6\x6D\xE5\xD6\x7E\x2E\x6D\xB6\xE9\x3A\x59\xCE\x0B\xB4' + b'\x81\x06\x09\x7F\xF7\x8A\x08\x1D\xE7\x81\xCD\xB3\x1F\xCE\x8C\xCB' + b'\xAA\xEA\x8D\xD4\x32\x0C\x41\x19\xF1\xE9\xCD\x43\x7A\x2E\xAB\x37' + b'\x31\xFA\x96\x68\xAB\x26\x8D\x87\x1D\xED\xA5\x5A\x54\x73\x19\x9F' + b'\x2F\xDC\x31\x30\x95\xBC\xDD\x5F\xB3\xA9\x16\x36\xF0\x7A\x95\x9C' + b'\x8E\x86\xB5\x63\x6A\x1E\x93\x0E\x83\x96\x04\x9C\xB4\x81\x96\x1D' + b'\x36\x5C\xC1\x14\x53\xA0\x6C\x71\x98\x35\x47\x5B\x12\xCB\x52\xFC' + b'\x3C\x38\x3B\xCE\x35\xE2\x7E\xF1\x94\x51\x2B\x71\x87\x62\x85\xFA' + ), + expected_pso_output=( + b'\xA7\x92\x70\x98\x65\x5F\x1F\x99\x76\xFA\x50\xA9\xD5\x66\x86\x5D' + b'\xC5\x30\x33\x18\x46\x38\x1C\x87\x25\x6B\xAF\x32\x26\x24\x4B\x76' + b'\xD3\x64\x03\xC0\x24\xD7\xBB\xF0\xAA\x08\x03\xEA\xFF\x40\x5D\x3D' + b'\x24\xF1\x1A\x9B\x5C\x0B\xEF\x67\x9F\xE1\x45\x4B\x21\xC4\xCD\x1F' + ), + ) diff --git a/tests/card_test_ed25519.py b/tests/card_test_ed25519.py new file mode 100644 index 0000000..25ec0d5 --- /dev/null +++ b/tests/card_test_ed25519.py @@ -0,0 +1,51 @@ +""" +card_test_ed25519.py - test ed25519 support + +Copyright (C) 2021 Vincent Pelletier + +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 . +""" + +import hashlib +from func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_ED25519(object): + def test_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(1, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc8032#section-7.3 + assert_ec_pso( + card=card, + key_index=0, + key_attributes=KEY_ATTRIBUTES_ED25519, + key_attribute_caption='ed25519', + private_key=( + b'\x83\x3f\xe6\x24\x09\x23\x7b\x9d\x62\xec\x77\x58\x75\x20\x91\x1e' + b'\x9a\x75\x9c\xec\x1d\x19\x75\x5b\x7d\xa9\x01\xb9\x6d\xca\x3d\x42' + ), + expected_public_key=( + b'\xec\x17\x2b\x93\xad\x5e\x56\x3b\xf4\x93\x2c\x70\xe1\x24\x50\x34' + b'\xc3\x54\x67\xef\x2e\xfd\x4d\x64\xeb\xf8\x19\x68\x34\x67\xe2\xbf' + ), + pso_input=hashlib.sha512(b'\x61\x62\x63').digest(), + expected_pso_output=( + b'\x98\xa7\x02\x22\xf0\xb8\x12\x1a\xa9\xd3\x0f\x81\x3d\x68\x3f\x80' + b'\x9e\x46\x2b\x46\x9c\x7f\xf8\x76\x39\x49\x9b\xb9\x4e\x6d\xae\x41' + b'\x31\xf8\x50\x42\x46\x3c\x2a\x35\x5a\x20\x03\xd0\x62\xad\xf5\xaa' + b'\xa1\x0b\x8c\x61\xe6\x36\x06\x2a\xaa\xd1\x1c\x2a\x26\x08\x34\x06' + ), + ) diff --git a/tests/card_test_x25519.py b/tests/card_test_x25519.py new file mode 100644 index 0000000..3418e89 --- /dev/null +++ b/tests/card_test_x25519.py @@ -0,0 +1,52 @@ +""" +card_test_x25519.py - test x25519 support + +Copyright (C) 2021 Vincent Pelletier + +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 func_pso_auth import assert_ec_pso +from card_const import * + +class Test_Card_X25519(object): + def test_reference_vectors(self, card): + assert card.verify(3, FACTORY_PASSPHRASE_PW3) + assert card.verify(2, FACTORY_PASSPHRASE_PW1) + # https://tools.ietf.org/html/rfc7748#section-6.1 + assert_ec_pso( + card=card, + key_index=1, + key_attributes=KEY_ATTRIBUTES_X25519, + key_attribute_caption='x25519', + private_key=( + b'\x77\x07\x6d\x0a\x73\x18\xa5\x7d\x3c\x16\xc1\x72\x51\xb2\x66\x45' + b'\xdf\x4c\x2f\x87\xeb\xc0\x99\x2a\xb1\x77\xfb\xa5\x1d\xb9\x2c\x2a' + ), + expected_public_key=( + b'\x85\x20\xf0\x09\x89\x30\xa7\x54\x74\x8b\x7d\xdc\xb4\x3e\xf7\x5a' + b'\x0d\xbf\x3a\x0d\x26\x38\x1a\xf4\xeb\xa4\xa9\x8e\xaa\x9b\x4e\x6a' + ), + pso_input=( + b'\xa6\x25\x7f\x49\x22\x86\x20' + b'\xde\x9e\xdb\x7d\x7b\x7d\xc1\xb4\xd3\x5b\x61\xc2\xec\xe4\x35\x37' + b'\x3f\x83\x43\xc8\x5b\x78\x67\x4d\xad\xfc\x7e\x14\x6f\x88\x2b\x4f' + ), + expected_pso_output=( + b'\x4a\x5d\x9d\x5b\xa4\xce\x2d\xe1\x72\x8e\x3b\xf4\x80\x35\x0f\x25' + b'\xe0\x7e\x21\xc9\x47\xd1\x9e\x33\x76\xf0\x9b\x3c\x1e\x16\x17\x42' + ), + ) diff --git a/tests/func_pso_auth.py b/tests/func_pso_auth.py new file mode 100644 index 0000000..43d0c40 --- /dev/null +++ b/tests/func_pso_auth.py @@ -0,0 +1,108 @@ +""" +func_pso_auth.py - functions for testing PSO commands + +Copyright (C) 2021 Vincent Pelletier + +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 . +""" + +import pytest +from card_const import KEY_ATTRIBUTES_RSA2K + +def _encodeDERLength(length): + if length < 0x80: + return length.to_bytes(1, 'big') + if length < 0x100: + return b'\x81' + length.to_bytes(1, 'big') + return b'\x82' + length.to_bytes(2, 'big') + +def get_ec_pso( + card, + key_index, + key_attributes, + key_attribute_caption, + private_key, expected_public_key, + pso_input, +): + """ + If card supports, change key attributes for given key slot, store + given private key, check that the card could derive the expected + public key from it, then call the appropriate PSO for this key slot + and return its result. + Sets key attributes to RSA2K before returning to caller. + Skips the test if initial key attribute change is rejected by the card. + """ + key_attribute_index, control_reference_template, pso_p1, pso_p2 = ( + (0xc1, b'\xb6\x00', 0x9e, 0x9a), # Sign + (0xc2, b'\xb8\x00', 0x80, 0x86), # Decrypt + (0xc3, b'\xa4\x00', 0x9e, 0x9a), # Authenticate + )[key_index] + try: + card.cmd_put_data(0x00, key_attribute_index, key_attributes) + except ValueError: + pytest.skip('No %s support' % (key_attribute_caption, )) + try: + private_key_len = len(private_key) + r = card.cmd_put_data_odd( + 0x3f, + 0xff, + b'\x4d' + _encodeDERLength(private_key_len + 10) + + control_reference_template + + b'\x7f\x48\x02' + b'\x92' + _encodeDERLength(private_key_len) + + b'\x5f\x48' + _encodeDERLength(private_key_len) + + private_key, + ) + assert r + r = card.cmd_get_public_key(key_index + 1) + expected_public_key_len = len(expected_public_key) + encoded_expected_public_key_len = _encodeDERLength( + expected_public_key_len, + ) + expected_public_key_response = ( + b'\x7f\x49' + _encodeDERLength( + expected_public_key_len + + len(encoded_expected_public_key_len) + 1, + ) + + b'\x86' + encoded_expected_public_key_len + + expected_public_key + ) + assert r == expected_public_key_response + return card.cmd_pso(pso_p1, pso_p2, pso_input) + finally: + card.cmd_put_data(0x00, key_attribute_index, KEY_ATTRIBUTES_RSA2K) + +def assert_ec_pso( + card, + key_index, + key_attributes, + key_attribute_caption, + private_key, expected_public_key, + pso_input, expected_pso_output, +): + """ + Calls get_ec_pso and checks if produced output matches the expected value. + """ + r = get_ec_pso( + card=card, + key_index=key_index, + key_attributes=key_attributes, + key_attribute_caption=key_attribute_caption, + private_key=private_key, + expected_public_key=expected_public_key, + pso_input=pso_input, + ) + assert r == expected_pso_output diff --git a/tests/test_006_pso.py b/tests/test_006_pso.py new file mode 100644 index 0000000..b8bc24b --- /dev/null +++ b/tests/test_006_pso.py @@ -0,0 +1,8 @@ +from card_test_ansix9p256r1 import * +from card_test_ansix9p384r1 import * +from card_test_ansix9p512r1 import * +from card_test_brainpoolp256r1 import * +from card_test_brainpoolp384r1 import * +from card_test_brainpoolp512r1 import * +from card_test_ed25519 import * +from card_test_x25519 import *