Compare commits

..

90 Commits

Author SHA1 Message Date
NIIBE Yutaka
b49390de7a add an entry in NEWS 2012-07-26 18:53:59 +09:00
NIIBE Yutaka
71eaffc0ee version 1.0 2012-07-21 09:36:25 +09:00
NIIBE Yutaka
5e9a35c881 doc 2012-07-21 09:27:08 +09:00
NIIBE Yutaka
df5b7f31a3 doc 2012-07-21 09:26:51 +09:00
NIIBE Yutaka
add6fa8b67 add document in Sphinx 2012-07-21 08:33:31 +09:00
NIIBE Yutaka
c488bed215 move old documents to doc/note 2012-07-21 08:32:53 +09:00
NIIBE Yutaka
63979416f6 fix tests for CERTDO 2012-07-20 16:00:41 +09:00
NIIBE Yutaka
92be182e8a update README for gcc-arm-embedded toolchain 2012-07-20 13:24:15 +09:00
NIIBE Yutaka
9ffa68355d update README for gcc-arm-embedded toolchain 2012-07-20 13:12:51 +09:00
NIIBE Yutaka
814f6b6329 update README 2012-07-20 13:04:39 +09:00
NIIBE Yutaka
1927f8a1ec update doc/ 2012-07-10 17:04:14 +09:00
NIIBE Yutaka
d3fb62b437 no keygen test cases 2012-07-10 17:03:50 +09:00
NIIBE Yutaka
5d3e6c2b29 initial PW1 123456 test cases 2012-07-10 14:16:53 +09:00
NIIBE Yutaka
8be278be17 not PW3 but PW1 2012-07-10 13:21:27 +09:00
NIIBE Yutaka
6de9c11329 test: fix signature counter 2012-07-10 10:36:15 +09:00
NIIBE Yutaka
63df97a2e0 Add tests 2012-07-10 08:55:48 +09:00
NIIBE Yutaka
144dd88a07 Bug fix for keygen 2012-07-10 08:51:38 +09:00
NIIBE Yutaka
e80c8f1e8e USB disconnect tool/stlinkv2.py 2012-07-10 08:50:32 +09:00
NIIBE Yutaka
99d7e8d396 reset is not needed as writ_prvkey does so 2012-07-09 15:16:56 +09:00
NIIBE Yutaka
f38f33dade bug fix for finish_gpio 2012-07-09 12:58:03 +09:00
NIIBE Yutaka
cbed6b49c7 LED off for -u 2012-07-09 10:19:01 +09:00
NIIBE Yutaka
51435e7dba return error sooner for decryption 2012-07-09 09:29:00 +09:00
NIIBE Yutaka
29b68186bf fix stlinkv2 for FST-01's LED 2012-07-09 09:27:38 +09:00
NIIBE Yutaka
a5fddc691d fix decryption test case 2012-07-09 09:26:10 +09:00
NIIBE Yutaka
965dace0a4 version 0.21 2012-07-06 10:21:58 +09:00
NIIBE Yutaka
ee4f3806c2 Add SPI flash ROM support for tool/stlinkv2.py 2012-07-06 10:03:10 +09:00
NIIBE Yutaka
9ad6c6461d SPI flash support starts for FST-01 2012-07-06 08:26:20 +09:00
NIIBE Yutaka
a796e9f145 RSA change 2012-07-05 09:32:46 +09:00
NIIBE Yutaka
f88e7af3ce add more tests 2012-07-05 09:26:58 +09:00
NIIBE Yutaka
fe31219d94 fix title 2012-07-05 09:13:32 +09:00
NIIBE Yutaka
6f97e8a7c4 Bug fix for s2k call 2012-07-05 09:12:04 +09:00
NIIBE Yutaka
e78206e1cd fix resetting ADMIN pass phrase in admi-less mode 2012-07-05 08:56:42 +09:00
NIIBE Yutaka
ffba0e0158 changelog 2012-07-04 06:00:14 +09:00
NIIBE Yutaka
324b648de8 test update 2012-07-03 19:32:15 +09:00
NIIBE Yutaka
9ef97836c9 Bug fix for changing PW3 2012-07-03 19:01:50 +09:00
NIIBE Yutaka
628c03634b Bug fix against flash GC 2012-07-03 18:36:24 +09:00
NIIBE Yutaka
315bef4639 Bug fix for PW1 2012-07-03 18:33:39 +09:00
NIIBE Yutaka
610573256e add new tests 2012-07-03 09:38:18 +09:00
NIIBE Yutaka
976e123413 more change for stlinkv2 2012-07-02 17:26:49 +09:00
NIIBE Yutaka
6f4c868336 file open with rb 2012-07-02 14:22:33 +09:00
NIIBE Yutaka
33c3980e46 fix stlinkv2.py (for Windows) 2012-07-02 13:55:21 +09:00
NIIBE Yutaka
6d8580f67a s2k 2012-06-30 07:49:40 +09:00
NIIBE Yutaka
506761d823 regnual cleanup 2012-06-29 13:45:37 +09:00
NIIBE Yutaka
09f22b114c update NEWS 2012-06-28 14:19:05 +09:00
NIIBE Yutaka
9f0b8ff4c3 removal of ~ 2012-06-28 12:58:58 +09:00
NIIBE Yutaka
2764bbb5a9 decryption test after keygen 2012-06-28 12:01:37 +09:00
NIIBE Yutaka
3202b7d45c add test for digital signature after keygen 2012-06-28 11:07:11 +09:00
NIIBE Yutaka
19e677ae74 add keygen test 2012-06-28 09:30:16 +09:00
NIIBE Yutaka
9cc6de9e65 naming: make it clear for crypt 2012-06-28 09:04:06 +09:00
NIIBE Yutaka
0988474d87 adding to gnuk.py 2012-06-28 09:03:15 +09:00
NIIBE Yutaka
d564e4a3c1 cleanup 2012-06-27 14:30:39 +09:00
NIIBE Yutaka
839b0156a9 more tests 2012-06-27 14:15:51 +09:00
NIIBE Yutaka
92d500d4b5 bug fix flash write and flash access before that while flash GC 2012-06-27 14:14:15 +09:00
NIIBE Yutaka
1944a78443 PW3 handling and signature counter 2012-06-27 13:10:12 +09:00
NIIBE Yutaka
e11d81376c key fingerprint and timestamp 2012-06-27 08:48:41 +09:00
NIIBE Yutaka
3c7a5bff61 fix string handling 2012-06-27 08:06:39 +09:00
NIIBE Yutaka
a41476ab32 add test 2012-06-26 17:59:24 +09:00
NIIBE Yutaka
1118cd030a usb_strings.py 2012-06-25 10:53:06 +09:00
NIIBE Yutaka
e6e11ddcb0 It's not like UNIX tools. 2012-06-22 17:00:35 +09:00
NIIBE Yutaka
5c5074c5c7 support FST-01 too 2012-06-22 15:33:03 +09:00
NIIBE Yutaka
d3f092a736 failure handling 2012-06-22 14:38:43 +09:00
NIIBE Yutaka
70efd3a1cd stlinkv2.py: Add blank check 2012-06-22 13:18:30 +09:00
NIIBE Yutaka
fd9f46bcc7 fix blank_check.S 2012-06-22 13:16:30 +09:00
NIIBE Yutaka
6f203bc4ea Add blank_check.S 2012-06-21 19:40:41 +09:00
NIIBE Yutaka
c25d98bc58 modify stlinkv2.py. 2012-06-20 17:31:27 +09:00
NIIBE Yutaka
4290a2cc10 ST-Link/V2 flash ROM writer 2012-06-20 14:44:20 +09:00
NIIBE Yutaka
b3c15ce93c version 0.20 2012-06-19 10:19:26 +09:00
NIIBE Yutaka
cb8ee10292 LED display output 2012-06-18 14:12:00 +09:00
NIIBE Yutaka
3df59ca6f9 LED display output 2012-06-18 14:04:34 +09:00
NIIBE Yutaka
6a4d7fa108 LED display output 2012-06-18 12:44:37 +09:00
NIIBE Yutaka
de51fc2fd4 LED display change 2012-06-18 12:24:54 +09:00
NIIBE Yutaka
c61a63dbb6 external authenticate incompatible change to SHA256 2012-06-16 14:33:22 +09:00
NIIBE Yutaka
e0282629e3 fix 2012-06-15 13:30:07 +09:00
NIIBE Yutaka
fe58e86c6c 512 2012-06-15 13:27:16 +09:00
NIIBE Yutaka
abd64bc495 clear random data after free 2012-06-15 13:26:27 +09:00
NIIBE Yutaka
2d5246e7fa protection improvements (2): Use ECB for DEK encryption, use IV, etc. 2012-06-15 08:56:57 +09:00
NIIBE Yutaka
94a65f0d99 Deprecate DnD 2012-06-15 08:55:09 +09:00
NIIBE Yutaka
2e5973e7cc fix clearing CTX 2012-06-14 16:00:07 +09:00
NIIBE Yutaka
a5d77ec5af protection improvement (1): different S2K for PW1 and Reset-code 2012-06-14 09:13:59 +09:00
NIIBE Yutaka
a2855c9442 use mpi_lset instead of mpi_read_string 2012-06-14 08:53:05 +09:00
NIIBE Yutaka
670e9058f1 SHA256 2012-06-14 08:46:59 +09:00
NIIBE Yutaka
81f8f94dd4 bug fix for LED display 2012-06-13 15:12:10 +09:00
NIIBE Yutaka
956e89d10a keygen is configure option 2012-06-13 09:07:26 +09:00
NIIBE Yutaka
ec0297050a polarssl bugfix 2012-06-08 11:01:05 +09:00
NIIBE Yutaka
258552e544 Emit LED light 2012-06-08 09:48:40 +09:00
NIIBE Yutaka
17fd82ffa1 Revert "improve bignum"
This reverts commit 3fa01ef7a9.
2012-06-07 15:37:40 +09:00
NIIBE Yutaka
3fa01ef7a9 improve bignum 2012-06-07 15:29:49 +09:00
NIIBE Yutaka
ee743ca042 internal authenticate input check 2012-06-07 13:59:13 +09:00
NIIBE Yutaka
39a3cb8b09 implement key generation 2012-06-07 13:12:27 +09:00
NIIBE Yutaka
2db7875da7 polarssl change 2012-06-07 10:39:48 +09:00
120 changed files with 5447 additions and 517 deletions

4
.gitignore vendored
View File

@@ -11,9 +11,7 @@ src/gnuk.elf
src/gnuk.hex
src/gnuk.map
src/*.inc
regnual/sys.h
regnual/regnual.bin
regnual/regnual.hex
regnual/regnual.elf
regnual/usb_lld.c
regnual/usb_lld.h
doc/_build

314
ChangeLog
View File

@@ -1,3 +1,317 @@
2012-07-21 Niibe Yutaka <gniibe@fsij.org>
* Version 1.0.
* src/usb_desc.c (gnukStringSerial): Updated.
Documentation by Sphinx.
* doc/Makefile: New.
* doc/note: Old notes are moved here.
2012-07-20 Niibe Yutaka <gniibe@fsij.org>
* test/features/002_get_data_static.feature: Support CERTDO enabled
Gnuk for the test of extended capabilities.
* test/features/802_get_data_static.feature: Ditto.
* test/features/402_get_data_static.feature: Ditto.
2012-07-10 Niibe Yutaka <gniibe@fsij.org>
* test/features/*: Add test cases for PW1/PW3 of factory settings.
* test/features/202_keygen.feature: Add PSO signature test after
keygen.
* test/features/602_keygen.feature: Ditto.
Bug fix.
* src/openpgp-do.c (gpg_do_write_prvkey): Don't call ac_reset_*
here.
(proc_key_import): But call ac_reset_* here.
(gpg_do_keygen): Load private key for signing.
* tool/stlinkv2.py (stlinkv2.usb_disconnect): New.
2012-07-09 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_pso): For decryption, return error sooner for
invalid data.
* tool/stlinkv2.py (stlinkv2.setup_gpio): Fix GPIOB_CRL.
* test/rsa_keys.py (integer_to_bytes_256): Rename from
integer_to_bytes and it should be exactly 256-byte long.
2012-07-06 Niibe Yutaka <gniibe@fsij.org>
* Version 0.21.
* src/usb_desc.c (gnukStringSerial): Updated.
* boards/FST_01/board.h (VAL_GPIOACRL): Change for SPI flash.
* tool/stlinkv2.py (stlinkv2.setup_gpio): Likewise.
(stlinkv2.spi_flash_init, stlinkv2.spi_flash_select)
(stlinkv2.spi_flash_sendbyte, stlinkv2.spi_flash_read_id): New.
(main): Add SPI flash ROM id check.
2012-07-05 Niibe Yutaka <gniibe@fsij.org>
* src/call-rsa.c (rsa_sign, rsa_decrypt): Don't need to setup N.
* polarssl-0.14.0/library/rsa.c (rsa_check_pubkey)
(rsa_check_privkey): Ifdef-out.
More tests.
* test/*: Add tests for admin-less mode.
* test/features/990_reset_passphrase.feature: This is now for
admin-less mode.
* test/features/970_key_removal.feature: Ditto.
* src/openpgp.c (cmd_change_password): Call ac_reset_admin when
admin-less mode.
(cmd_reset_user_password): Likewise.
* src/ac.c (ac_reset_admin, ac_fini): Clear ADMIN_AUTHORIZED.
Bug fix.
* src/ac.c (verify_admin): Call s2k with ADMIN_AUTHORIZED.
2012-07-04 Niibe Yutaka <gniibe@fsij.org>
Bug fixes.
* src/ac.c (verify_admin_0): Compare PW_LEN and BUF_LEN.
* src/openpgp-do.c (gpg_do_chks_prvkey): Set do_ptr to NULL before
calling flash_do_write (which might cause GC).
(gpg_do_put_data, gpg_do_write_simple): Likewise.
* src/openpgp.c (cmd_reset_user_password): Write to
DO_KEYSTRING_PW1.
2012-07-03 Niibe Yutaka <gniibe@fsij.org>
* test/features/040_passphrase_change.feature: New.
* test/features/203_passphrase_change.feature: New.
* test/features/210_compute_signature.feature: Rename (was:
203_compute_signature.feature)
* test/features/211_decryption.feature: Rename (was:
204_decryption.feature)
2012-07-02 Niibe Yutaka <gniibe@fsij.org>
* tool/stlinkv2.py (stlinkv2.__init__): Don't call setAltInterface.
2012-06-30 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (s2k): New.
(resetcode_s2k): Remove.
(cmd_reset_user_password, cmd_change_password): Use s2k (was:
sha256 directly or resetcode_s2k).
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey):
Likewise.
* src/ac.c (verify_user_0, verify_admin): Likewise.
2012-06-29 Niibe Yutaka <gniibe@fsij.org>
* regnual/Makefile: Don't copy usb_lld.c.
2012-06-28 Niibe Yutaka <gniibe@fsij.org>
* test/features/204_decryption.feature: New.
* test/features/203_compute_signature.feature: New.
* test/features/202_keygen.feature: New.
* test/features/201_setup_passphrase.feature: New.
* test/features/200_key_removal.feature: New.
* test/rsa_keys.py (verify_signature): New.
(encrypt_with_pubkey): New.
* test/gnuk.py (gnuk_token): New method: increment_seq.
(gnuk_token.icc_send_cmd): Handle timeout.
(gnuk_token.cmd_genkey): New.
(gnuk_token.cmd_get_public_key): New.
2012-06-27 Niibe Yutaka <gniibe@fsij.org>
* test/features/101_decryption.feature: New.
* test/features/100_compute_signature.feature: New.
* src/openpgp-do.c (gpg_do_chks_prvkey): Call flash_do_release before
flash_do_write.
(gpg_do_write_prvkey): Bug fix when GC occurs.
* src/openpgp.c (cmd_change_password): Support resetting to
factory setting of PW3.
* src/openpgp-do.c (gpg_do_write_prvkey): Don't reset signagure
counter here.
(proc_key_import): But reset here.
Call ac_reset_* when key is imported.
2012-06-26 Niibe Yutaka <gniibe@fsij.org>
* test: New.
2012-06-25 Niibe Yutaka <gniibe@fsij.org>
* tool/usb_strings.py: New.
2012-06-22 Niibe Yutaka <gniibe@fsij.org>
* tool/stlinkv2.py (stlinkv2.blank_check): Add blank check of
Flash ROM.
2012-06-21 Niibe Yutaka <gniibe@fsij.org>
* tool/asm-thumb/blank_check.S: New.
2012-06-20 Niibe Yutaka <gniibe@fsij.org>
ST-Link/V2 flash ROM writer.
* tool/stlinkv2.py: New.
* tool/asm-thumb/opt_bytes_write.S: New.
* tool/asm-thumb/flash_write.S: New.
2012-06-19 Niibe Yutaka <gniibe@fsij.org>
* Version 0.20.
* src/usb_desc.c (gnukStringSerial): Updated.
2012-06-18 Niibe Yutaka <gniibe@fsij.org>
LED display output change.
* src/main.c (MAIN_TIMEOUT_INTERVAL): New.
(LED_TIMEOUT_INTERVAL, etc.): New values.
(main_mode, display_interaction): Remove.
(led_inverted, emit_led): New.
(display_status_code): Use emit_led.
(led_blink): Use LED_* for SPEC.
(main, fatal): New LED display output.
* src/gnuk.h (LED_ONESHOT, LED_TWOSHOTS, LED_SHOW_STATUS)
(LED_START_COMMAND, LED_FINISH_COMMAND, LED_FATAL): New semantics.
(main_thread): Remove.
* src/openpgp-do.c (gpg_do_keygen): Don't touch LED here.
* src/openpgp.c (get_pinpad_input): Call led_blink.
(cmd_pso, cmd_internal_authenticate): Don't touch LED here.
(GPGthread): Call led_blink.
* src/pin-cir.c (pinpad_getline): Change arg of led_blink.
* src/pin-dnd.c (pinpad_getline): Ditto.
* src/usb-icc.c (icc_handle_timeout): Ditto.
(icc_send_status): Call led_blink.
* src/usb_ctrl.c (gnuk_usb_event): Don't touch LED here.
2012-06-16 Niibe Yutaka <gniibe@fsij.org>
Use SHA256 format for "external authenticate".
* tool/gnuk_upgrade.py (gpg_sign): SHA256 sign by "SCD PKAUTH".
(main): Not specify keygrip, but always use key for authentication.
* src/call-rsa.c (rsa_verify): It is SHA256 format (was: SHA1).
* src/openpgp.c (cmd_get_challenge): Don't add chip-id prefix.
(cmd_external_authenticate): Likewise.
2012-06-15 Niibe Yutaka <gniibe@fsij.org>
* src/random.c (random_bytes_free): Clear out random bytes.
More protection improvements.
* src/random.c (RANDOM_BYTES_LENGTH): It's 32 now (was: 16).
* src/gnuk.h (struct key_data_internal): Remove check, random,
magic. Add checksum.
(struct prvkey_data): Remove crm_encrypted. Add iv and
checksum_encrypted.
* src/openpgp-do.c (encrypt, decrypt): Add IV argument.
(encrypt_dek, decrypt_dek): New. It's in ECB mode.
(compute_key_data_checksum): New.
(gpg_do_load_prvkey): Handle initial vector and checksum.
Use decrypt_dek to decrypt DEK. Clear DEK after use.
(calc_check32):Remove.
(gpg_do_write_prvkey): Use encrypt_dek to encrypt DEK.
(gpg_do_chks_prvkey): Likewise.
* polarssl-0.14.0/include/polarssl/aes.h (aes_crypt_cbc)
* polarssl-0.14.0/library/aes.c (aes_crypt_cbc): ifdef-out.
* src/configure (--enable-pinpad): Deprecate DND.
2012-06-14 Niibe Yutaka <gniibe@fsij.org>
Protection improvement.
* src/openpgp.c (resetcode_s2k): New.
(cmd_reset_user_password): Use resetcode_s2k.
* src/openpgp-do.c (proc_resetting_code): Likewise.
* src/sha256.c (sha256_finish): Clear out CTX at the end.
* src/call-rsa.c (rsa_sign, rsa_decrypt, rsa_verify): Use
mpi_lset (was: mpi_read_string).
* polarssl-0.14.0/library/bignum.c (mpi_get_digit)
(mpi_read_string): ifdef-out.
KDF is now SHA-256 (was: SHA1).
* src/sha256.c: New file. Based on the implementation by Dr Brian
Gladman.
* src/openpgp.c (cmd_change_password, cmd_reset_user_password):
Use sha256.
* src/openpgp-do.c (proc_resetting_code, gpg_do_write_prvkey): Likewise.
* src/ac.c (verify_user_0, calc_md, verify_admin): Likewise.
* src/crypt.mk (CRYPTSRC): Add sha256.c, removing sha1.c.
* src/gnuk.h (KEYSTRING_MD_SIZE): It's 32 for SHA-256.
2012-06-13 Niibe Yutaka <gniibe@fsij.org>
Bug fixes.
* src/main.c (display_interaction): Assign to main_mode.
* src/openpgp.c (cmd_change_password): Bug fix for admin less mode
to admin full mode. Variable who_old should be admin_authorized.
Key generation is configure option.
* src/configure (keygen): Add --enable-keygen option.
* src/Makefile.in (UDEFS): Add definition of KEYGEN_SUPPORT.
* src/call-rsa.c [KEYGEN_SUPPORT] (rsa_genkey): Conditionalize.
* src/random.c [KEYGEN_SUPPORT] (random_byte): Ditto.
* src/openpgp.c [KEYGEN_SUPPORT] (cmd_pgp_gakp): Ditto.
* src/openpgp-do.c [KEYGEN_SUPPORT] (gpg_do_keygen): Ditto.
* polarssl-0.14.0/include/polarssl/config.h: Ditto.
* polarssl-0.14.0/library/bignum.c [POLARSSL_GENPRIME]
(mpi_inv_mod): Unconditionalize.
2012-06-08 Niibe Yutaka <gniibe@fsij.org>
* polarssl-0.14.0/library/bignum.c (mpi_cmp_mpi): Bug fix.
Though it doesn't matter for Gnuk usage.
Emit LED light while computation (or asking user input).
* src/usb-icc.c (icc_handle_timeout): Call led_blink.
* src/openpgp.c (cmd_pso, cmd_internal_authenticate): Call
LED_WAIT_MODE, LED_STATUS_MODE to show "it's under computation".
* src/openpgp-do.c (gpg_do_keygen): Ditto.
* src/gnuk.h (LED_WAIT_MODE): Rename (was: LED_INPUT_MODE).
* src/main.c (display_interaction): Change the behavior of LED,
now, it's mostly ON (was: mostly OFF).
2012-06-07 Niibe Yutaka <gniibe@fsij.org>
* src/openpgp.c (cmd_internal_authenticate): Add check for input
length.
Implement key generation.
* src/openpgp.c (cmd_pgp_gakp): Call gpg_do_keygen.
* src/openpgp-do.c (proc_key_import): Call with modulus = NULL.
(gpg_do_keygen): New function.
(gpg_reset_digital_signature_counter): New function.
(gpg_do_write_prvkey): New argument MODULUS. Call
gpg_reset_digital_signature_counter.
* src/call-rsa.c (rsa_genkey): New function.
* src/random.c (random_byte): New function.
PolarSSL modification.
* polarssl-0.14.0/library/rsa.c (rsa_gen_key): Don't set D, DP,
DQ, and QP. It's only for key generation.
* polarssl-0.14.0/library/rsa.c (rsa_gen_key, rsa_pkcs1_encrypt):
Change f_rng function return type.
* polarssl-0.14.0/include/polarssl/rsa.h: Likewise.
* polarssl-0.14.0/library/bignum.c (mpi_is_prime, mpi_gen_prime):
Change f_rng function return type.
* polarssl-0.14.0/include/polarssl/bignum.h: Likewise.
2012-06-06 Niibe Yutaka <gniibe@fsij.org>
* Version 0.19.

63
NEWS
View File

@@ -1,5 +1,68 @@
Gnuk NEWS - User visible changes
* Major changes in Gnuk 1.0
Released 2012-07-21, by NIIBE Yutaka
This is bug fixes only release.
* Major changes in Gnuk 0.21
Released 2012-07-06, by NIIBE Yutaka
** Test suite
A functinality test suite is added under test/ directory.
** New tool: stlinkv2.py
This tool is SWD flash ROM writer with ST-Link/V2.
** New tool: usb_strings.py
This tool is to dump USB strings, which include revision detail and config
options.
** Protection improvement (even when internal data is disclosed)
Even if PW1 and PW3 is same, content of encrypted DEK is different
now.
* Major changes in Gnuk 0.20
Released 2012-06-19, by NIIBE Yutaka
** Key generation feature added
Finally, key generation is supported. Note that it may be very slow.
It may take a few minutes (or more) to generate two or three keys,
when you are unlucky.
** DnD pinentry support is deprecated
Once, DnD pinentry was considered a great feature, but it found that
it is difficult to remember moves of folders.
** gnuk_upgrade.py assumes using another token for authentication
Use of another token for authentication is assumed now. This is
incompatible change. Note that when you upgrade a token of version
0.19 to 0.20 (or later), you need gnuk_upgrade.py of version 0.19.
** KDF (Key Derivation Function) is now SHA-256
Keystring is now computed by SHA-256 (it was SHA1 before).
** Protection improvements (even when internal data is disclosed)
Three improvements. (1) Even if PW1 and Reset-code is same, content
of encrypted DEK is different now. (2) DEK is now encrypted and
decrypted by keystring in ECB mode (it was just a kind of xor by
single block CFB mode). (3) Key data plus checksum are encrypted in
CFB mode with initial vector (it will be able to switch OCB mode
easily).
** LED display output change
LED display output by Gnuk is now more reactive. It shows status code
when it gets GET_STATUS message of CCID. When you communicate Gnuk by
internal CCID driver of GnuPG (instead of PC/SC), and enable
'debug-disable-ticker' option in .gnupg/scdaemon.conf, it is more
silent now.
* Major changes in Gnuk 0.19
Released 2012-06-06, by NIIBE Yutaka

133
README
View File

@@ -1,15 +1,15 @@
Gnuk - software for GnuPG USB Token
Gnuk - An Implementation of USB Cryptographic Token for GnuPG
Version 0.19
2012-06-06
Version 1.0
2012-07-21
Niibe Yutaka
Free Software Initiative of Japan
What's Gnuk?
============
Gnuk is software implementation of a USB token for GNU Privacy Guard.
Gnuk supports OpenPGP card protocol version 2, and it runs on
Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on
STM32F103 processor.
I wish that Gnuk will be a developer's soother who uses GnuPG. I have
@@ -19,8 +19,8 @@ to bring a card reader all the time. With Gnuk, this issue will be
solved by a USB token which is small enough.
Please look at the graphics of "gnuk.svg" for the software name. My
son used to be with his NUK(R), always, everywhere. I am with a USB
Token by "Gnuk", always, everywhere.
son used to be with his NUK(R), always, everywhere. Now, I am with a
USB Cryptographic Token by "Gnuk", always, everywhere.
FAQ
@@ -30,11 +30,7 @@ Q0: How Gnuk USB Token is superior than other solutions (OpenPGP
card 2.0, GPF Crypto Stick, etc.) ?
http://www.g10code.de/p-card.html
http://www.privacyfoundation.de/crypto_stick/
A0: IMRHO, not quite, since there is no ready-to-use out-of-box Gnuk
product yet. (It is welcome for me that some vendor will
manufacture Gnuk USB Token. Even I can help design of hardware,
if needed.)
Good points for Gnuk are:
A0: Good points of Gnuk are:
* If you have skill of electronics and like DIY, you can build
Gnuk Token cheaper (see Q8-A8).
* You can study Gnuk to modify and to enhance. For example, you
@@ -60,7 +56,7 @@ A3: Orthodox choice is Olimex STM32-H103.
Q4: What's version of GnuPG are you using?
A4: In Debian GNU/Linux system, I use gnupg 1.4.11-3 and gnupg-agent
2.0.14-2 (in sid). With older versions, you can only sign with SHA1.
2.0.18-2. With older versions, you can only sign with SHA1.
See: http://www.fsij.org/gnuk/gnupg2-fixes-needed
Q5: What's version of pcscd and libccid are you using?
@@ -83,13 +79,18 @@ A8: STM8S Discovery Kit costs 750 JPY (< $10 USD) only. You can build
http://www.fsij.org/gnuk/jtag_dongle_ftdi2232
Q9: I got an error like "gpg: selecting openpgp failed: ec=6.108", what's up?
A9: GnuPG's SCDaemon has problems for handling insertion/removal of
card/reader (problems are fixed in trunk). When your newly
inserted token is not found by GnuPG, try killing scdaemon and let
it to be invoked again. I do:
$ killall -9 scdaemon
card/reader (problems are fixed in trunk, and backported to 2.0
branch, it will be 2.0.20). When your newly inserted token is not
found by GnuPG, try killing scdaemon and let it to be invoked
again. I do:
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
and confirm scdaemon doesn't exist, then,
$ gpg-connect-agent learn /bye
$ gpg-connect-agent learn /bye
Qa: With GNOME 2, I can't use Gnuk Token for SSH. How can we use it for SSH?
Aa: You need to deactivate seahorse-agent and gnome-keyring, but use
@@ -106,16 +107,17 @@ Ab: That's because gnome-keyring-daemon interferes GnuPG. Type:
"GPG Password Agent" and "SSH Key Agent".
Qc: Do you know a good SWD debugger to connect FST-01 or something?
Ac: STLink v2 is cheap one. See http://code.google.com/p/arm-utilities/
for a control program.
Ac: STLink v2 is cheap one. We have a tool/stlinkv2.py as flash ROM
writer program.
Release notes
=============
This is twentieth release of Gnuk. In this release, firmware upgrade
feature is added. While it is daily use, some features (including
firmware upgrade) are still considered experimental.
This is version 1.0 release of Gnuk, after a year and eleven months
development. While it is daily use for a year or so, some newly
introduced features (including key generation and firmware upgrade)
should be considered experimental.
Tested features are:
@@ -132,9 +134,17 @@ Tested features are:
* Changing value of password status bytes (0x00C4): forcesig
* Verify with pin pad
* Modify with pin pad
* Card holder certificate
* Removal of keys (Overriding key import is not supported,
* Card holder certificate (read)
* Removal of keys
(Overriding key import is not supported,
but you can remove all keys to import again).
* Key generation on device side
Original features of Gnuk, tested lightly:
* OpenPGP card serial number setup
* Card holder certificate (write by UPDATE BINARY)
* Upgrading with "EXTERNAL AUTHENTICATE" by reGNUal
It is known not-working well:
@@ -142,9 +152,11 @@ It is known not-working well:
work well. Please make sure to disable DEBUG option if it
doesn't work well.
Not supported feature(s):
* Key generation on device side
It is known that the combination of libccid 1.4.1 (or newer) with
libusb 1.0.8 (or older) has a minor problem. It is rare but it is
possible for USB communication to be failed, because of a bug in
libusb implementation. Use libusbx 1.0.9 or newer, or don't use
PC/SC, but use internal CCID driver of GnuPG.
Targets
@@ -174,13 +186,6 @@ Another PIN-pad support is connecting rotary encoder, push switch and
7-segment LED display. Both of PIN verification and PIN modification
are supported for this circuit extension.
Also, there is "DnDpinentry" support. This is using usual file
manager for pinentry. User does "drag and drop" folders and it will
be pin entry. This feature doesn't require any additional hardware.
See doc/settings-for-DnDpinentry for your desktop configuration.
However, this will be removed in future version, as it found it's
not that useful.
Note that you need pinpad support for GnuPG to use PIN-pad enabled
Gnuk. The pinpad support for GnuPG is currently in the master branch
of GnuPG git repository at git.gnupg.org, and it's under evaluation.
@@ -192,6 +197,11 @@ Souce code
Gnuk source code is under src/ directory.
Note that SHA-2 hash function implementation, src/sha256.c, is based
on the original implementation by Dr. Brian Gladman. See:
http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
License
=======
@@ -200,7 +210,7 @@ It is distributed under GNU General Public Licence version 3 or later
(GPLv3+). Please see src/COPYING.
Please note that it is distributed with external source code too.
Please read relevant licenses for external source code, too.
Please read relevant licenses for external source code as well.
The author(s) of Gnuk expect users of Gnuk will be able to access the
source code of Gnuk, so that users can study the code and can modify
@@ -224,12 +234,18 @@ Gnuk is distributed with external source code.
* polarssl-0.14.0/ -- PolarSSL 0.14.0
Taken from http://polarssl.org/
We use PolarSSL for RSA computation, AES encryption/decryption
and SHA-1 computation.
We use PolarSSL for RSA computation, AES encryption/decryption.
The file include/polarssl/bn_mul.h is heavily modified for ARM
Cortex-M3.
The files include/polarssl/rsa.h, library/rsa.c,
include/polarssl/bignum.h, and library/bignum.c are modified so that
f_rng function returns unsigned char.
The file library/rsa.c is modified so that it only computes things
needed for Gnuk.
The file library/aes.c is modified so that some constants can
go to .sys section.
@@ -276,15 +292,16 @@ respect users' freedom for computing. Please ask FSIJ for the
license.
Otherwise, companies which want to distribute Gnuk devices, please use
your own USB vendor ID and product ID. Note that please replace
"FSIJ" in the string gnukStringSerial (usb_desc.c) to yours, when you
modify Gnuk.
your own USB vendor ID and product ID. Please replace "FSIJ" in the
string gnukStringSerial (usb_desc.c) to yours, when you modify Gnuk.
Host Requirements
=================
For GNU/Linux, libccid version >= 1.3.11 is recommended.
For GNU/Linux, PC/SC service is an option, you can use GnuPG's
internal CCID driver instead. If you chose using PC/SC service,
libccid version >= 1.3.11 is recommended for GNU/Linux.
I think that it should not be requirment but the kernel version of my use is:
Linux version 2.6.32-5-686 (Debian 2.6.32-18) (ben@decadent.org.uk) (gcc version 4.3.5 (Debian 4.3.5-2) ) #1 SMP Sat Jul 24 02:27:10 UTC 2010
@@ -300,7 +317,7 @@ You need GNU toolchain and newlib for 'arm-none-eabi' target.
See http://github.com/esden/summon-arm-toolchain/ (which includes fix
of binutils-2.21.1) for preparation of GNU Toolchain for
'arm-none-eabi' target.
'arm-none-eabi' target. This is for GCC 4.5.
# Note that we need to link correct C library (for string functions).
# For this purpose, Makefile.in contains following line:
@@ -316,6 +333,13 @@ of binutils-2.21.1) for preparation of GNU Toolchain for
# -mno-thumb-interwork option. This means that you should not
# link C library which contains ARM (not Thumb) code.
Recently, there is "gcc-arm-embedded" project. See:
https://launchpad.net/gcc-arm-embedded/
It is based on GCC 4.6. For version 4.6-2012-q2-update, you'd
need "-O3 -Os" instead of "-O2" and it will be slightly better.
Change directory to `src':
@@ -463,7 +487,7 @@ PyUSB (python-usb package in Debian).
If scdaemon is running, please kill it, or you will get "Smartcard
Exception" by "Sharing violation".
$ killall -9 scdaemon
$ gpg-connect-agent "SCD KILLSCD" "SCD BYE" /bye
In case of PyUSB tool, you need to stop pcscd.
@@ -542,11 +566,15 @@ This entry has been added into libccid 1.4.1 already ([r5425]).
Testing Gnuk
------------
Try following to see Gnuk runs:
Type following command to see Gnuk runs:
$ gpg --card-status
Besides, there is a functinality test under test/ directory. See
test/README.
Personalize the Token and import keys
-------------------------------------
@@ -559,18 +587,21 @@ command is:
Note that the factory setting of user password is "123456" and admin
password is "12345678" as the specification.
No, Gnuk doesn't support key generation. You need to create your
keys on your computer, and import them to Gnuk Token. After you create
your keys (they must be 2048-bit RSA), you can import them.
It is recommended to create your keys on your computer, and import
them to Gnuk Token. After you create your keys (they must be 2048-bit
RSA), you can import them.
For detail, please see doc/DEMO and doc/DEMO-2.
Gnuk supports key generation, but this feature is young and should be
considered experimental.
For detail, please see doc/note/DEMO and doc/note/DEMO-2.
Note that it make sense to preserve your keys on your computer so that
you can import the keys (again) to (possibly another) Gnuk Token. In
this case, you can use GnuPG's option to specify the home directory by
--homedir.
After creating keys by:
After creating keys on your computer by:
$ gpg --gen-key
...
@@ -625,7 +656,7 @@ linux/Documentation/usb/usbmon.txt
Firmware update
===============
See doc/firmware-update.
See doc/note/firmware-update.
Read-only Git Repository

View File

@@ -97,12 +97,15 @@
* PA0 - input with pull-up (TIM2_CH1)
* PA1 - input with pull-down (TIM2_CH2)
* PA2 - input with pull-up (TIM2_CH3)
* PA4 - Push pull output (SPI1_NSS)
* PA5 - Alternate Push pull output (SPI1_SCK)
* PA6 - Alternate Push pull output (SPI1_MISO)
* PA7 - Alternate Push pull output (SPI1_MOSI)
* PA10 - Push pull output (USB 1:ON 0:OFF)
* PA11 - input with pull-up (USBDM)
* PA12 - input with pull-up (USBDP)
* Everything input with pull-up except:
* PA10 - Push pull output (USB 1:ON 0:OFF)
*/
#define VAL_GPIOACRL 0x88888888 /* PA7...PA0 */
#define VAL_GPIOACRL 0xBBB38888 /* PA7...PA0 */
#define VAL_GPIOACRH 0x88888388 /* PA15...PA8 */
#define VAL_GPIOAODR 0xFFFFFFFD

153
doc/Makefile Normal file
View File

@@ -0,0 +1,153 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER = a4
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/GnukDocumentation.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/GnukDocumentation.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/GnukDocumentation"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/GnukDocumentation"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

246
doc/conf.py Normal file
View File

@@ -0,0 +1,246 @@
# -*- coding: utf-8 -*-
#
# Gnuk Documentation documentation build configuration file, created by
# sphinx-quickstart on Wed Jul 4 15:29:05 2012.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Gnuk Documentation'
copyright = u'2012, Niibe Yutaka'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'GnukDocumentationdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'GnukDocumentation.tex', u'Gnuk Documentation Documentation',
u'Niibe Yutaka', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'gnukdocumentation', u'Gnuk Documentation Documentation',
[u'Niibe Yutaka'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'GnukDocumentation', u'Gnuk Documentation Documentation',
u'Niibe Yutaka', 'GnukDocumentation', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'http://docs.python.org/': None}

60
doc/development.rst Normal file
View File

@@ -0,0 +1,60 @@
Development Environment
=======================
Hardware
--------
JTAG debugger or SWD debugger is required.
GNU Toolchain
-------------
You need GNU toolchain and newlib for 'arm-none-eabi' target.
See http://github.com/esden/summon-arm-toolchain/ (which includes fix
of binutils-2.21.1) for preparation of GNU Toolchain for
'arm-none-eabi' target. This is for GCC 4.5.
Note that we need to link correct C library (for string functions).
For this purpose, our src/Makefile.in contains following line:
MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
This should not be needed (as -mcpu=cortex-m3 means
-mfix-cortex-m3-ldrd), but it is needed for the configuration of
patch-gcc-config-arm-t-arm-elf.diff in summon-arm-toolchain in practice.
In ChibiOS_2.0.8/os/ports/GCC/ARM/rules.mk, it specifies
-mno-thumb-interwork option. This means that you should not link C
library which contains ARM (not Thumb) code.
Recently, there is "gcc-arm-embedded" project. See:
https://launchpad.net/gcc-arm-embedded/
It is based on GCC 4.6. For version 4.6-2012-q2-update, you'd
need "-O3 -s" instead of "-O2" and it will be slightly better.
Building Gnuk
-------------
Change directory to ``src``:
$ cd gnuk-VERSION/src
Then, run ``configure``:
$ ./configure --vidpid=<VID:PID>
Here, you need to specify USB vendor ID and product ID. For FSIJ's,
it's: --vidpid=234b:0000 . Please read section 'USB vendor ID and
product ID' above.
Type:
$ make
Then, we will have "gnuk.elf".

24
doc/index.rst Normal file
View File

@@ -0,0 +1,24 @@
.. Gnuk Documentation documentation master file, created by
sphinx-quickstart on Wed Jul 4 15:29:05 2012.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Gnuk Documentation
==================
Contents:
.. toctree::
:maxdepth: 2
intro.rst
development.rst
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

45
doc/intro.rst Normal file
View File

@@ -0,0 +1,45 @@
Introduction
============
What's Gnuk?
------------
Gnuk is an implementation of USB cryptographic token for GNU Privacy
Guard. Gnuk supports OpenPGP card protocol version 2, and it runs on
STM32F103 processor.
Cryptographic token and feature of Gnuk
---------------------------------------
Cryptographic token is a store of private keys and it computes cryptographic functions on the device.
Development Environment
-----------------------
See :doc:`development` for development environment for Gnuk. It builds on Free Software.
Prerequisites
-------------
* GNU Privacy Guard (GnuPG)
* libusb
* [Optional] PC/SC lite (pcscd, libccid)
* SSH: openssh
* Web: scute, firefox
Usage
-----
* Sign with GnuPG
* Decrypt with GnuPG
* Use with OpenSSH
* Use with Firefox for X.509 client certificate authentication

View File

@@ -1,4 +1,4 @@
* Random Number Generator
* [DONE] Random Number Generator
RNG is needed for Data Encryption Key to encrypt private key (P and Q).
It is important to collect enough entropy. Perhaps, it would

View File

@@ -77,7 +77,8 @@ KEYPTR
<---encrypted----><--- plain ---->
key_addr 4-byte
additional_data_encrypted 16-byte
initial_vector (random) 16-byte
checksum_encrypted 16-byte
dek_encrypted_by_keystring_pw1 16-byte
dek_encrypted_by_keystring_rc 16-byte
dek_encrypted_by_keystring_pw3 16-byte
@@ -85,6 +86,4 @@ dek_encrypted_by_keystring_pw3 16-byte
... decrypted to
[ P ][ Q ]
check 4-byte
random 4-byte
magic[] 8-byte
checksum 16-byte

View File

@@ -8,7 +8,6 @@ Note that updating firmware, all data objects and keys will be
removed. There is _no way_ to preserve those data.
Preparation
===========
@@ -96,9 +95,9 @@ Then, we can put the data of public key into token by::
Invoking firmware update
========================
We specify the keygrip to authenticate, reGNUal binary, and Gnuk binary.
We specify reGNUal binary and Gnuk binary.
$ ../tool/gnuk_upgrade.py 5D6C89682D07CCFC034AF508420BF2276D8018ED ../regnual/regnual.bin gnuk.bin
$ ../tool/gnuk_upgrade.py ../regnual/regnual.bin gnuk.bin
Two or more tokens
@@ -107,9 +106,9 @@ Two or more tokens
Currently, GnuPG doesn't support multiple devices connected to the
host.
In order to update the firmware of a token TARGET, we use GnuPG to
authenticate with public key. If it is on another token AUTH, it is
somewhat complicated.
In order to update the firmware of a TARGET token, we use GnuPG to
authenticate with public key. It is assumed that you have another
AUTH token for this. This situation is somewhat complicated.
What I do is:
(1) Don't run PC/SC daemon::
@@ -120,9 +119,14 @@ What I do is:
$ killall -9 scdaemon
(3) Connect the token of AUTH, and use it::
(3) Insert the AUTH token to USB, and use it::
$ gpg --card-status
(4) Connect TARGET, and invoke gnuk_update.py
(4) Insert the TARGET token to USB (after scdaemon communicates AUTH
token), and invoke gnuk_upgrade.py.
In this situation, gnuk_upgrade.py tries to connect one of tokens,
but a connection to the AUTH token will fail because scdaemon is
connecting to that device, and will be expected to connect to the
TARGET token succesufully, instead.
--

View File

@@ -83,6 +83,7 @@ int aes_crypt_ecb( aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] );
#if 0
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
@@ -103,6 +104,7 @@ int aes_crypt_cbc( aes_context *ctx,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif
/**
* \brief AES-CFB128 buffer encryption/decryption.

View File

@@ -501,7 +501,7 @@ int mpi_inv_mod( mpi *X, const mpi *A, const mpi *N );
* 1 if memory allocation failed,
* POLARSSL_ERR_MPI_NOT_ACCEPTABLE if X is not prime
*/
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng );
/**
* \brief Prime number generation
@@ -517,7 +517,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng );
* POLARSSL_ERR_MPI_BAD_INPUT_DATA if nbits is < 3
*/
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
int (*f_rng)(void *), void *p_rng );
unsigned char (*f_rng)(void *), void *p_rng );
/**
* \brief Checkup routine

View File

@@ -86,10 +86,12 @@
*/
#define POLARSSL_VERSION_C
#ifdef KEYGEN_SUPPORT
/*
* Enable the prime-number generation code.
*/
#define POLARSSL_GENPRIME
#endif
/*
* Uncomment this macro to store the AES tables in ROM.

View File

@@ -183,7 +183,7 @@ void rsa_init( rsa_context *ctx,
* \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *),
unsigned char (*f_rng)(void *),
void *p_rng,
int nbits, int exponent );
@@ -258,7 +258,7 @@ int rsa_private( rsa_context *ctx,
* of ctx->N (eg. 128 bytes if RSA-1024 is used).
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *),
unsigned char (*f_rng)(void *),
void *p_rng,
int mode, int ilen,
const unsigned char *input,

View File

@@ -753,6 +753,7 @@ int aes_crypt_ecb( aes_context *ctx,
return( 0 );
}
#if 0
/*
* AES-CBC buffer encryption/decryption
*/
@@ -816,6 +817,7 @@ int aes_crypt_cbc( aes_context *ctx,
return( 0 );
}
#endif
/*
* AES-CFB128 buffer encryption/decryption

View File

@@ -225,6 +225,7 @@ int mpi_size( const mpi *X )
return( ( mpi_msb( X ) + 7 ) >> 3 );
}
#if 0
/*
* Convert an ASCII character to digit value
*/
@@ -310,7 +311,6 @@ cleanup:
return( ret );
}
#if 0
/*
* Helper to write the digits high-order first
*/
@@ -649,7 +649,7 @@ int mpi_cmp_mpi( const mpi *X, const mpi *Y )
return( 0 );
if( i > j ) return( X->s );
if( j > i ) return( -X->s );
if( j > i ) return( -Y->s );
if( X->s > 0 && Y->s < 0 ) return( 1 );
if( Y->s > 0 && X->s < 0 ) return( -1 );
@@ -1570,8 +1570,6 @@ cleanup:
return( ret );
}
#if defined(POLARSSL_GENPRIME)
/*
* Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64)
*/
@@ -1665,6 +1663,8 @@ cleanup:
return( ret );
}
#if defined(POLARSSL_GENPRIME)
static const int small_prime[] =
{
3, 5, 7, 11, 13, 17, 19, 23,
@@ -1693,7 +1693,7 @@ static const int small_prime[] =
/*
* Miller-Rabin primality test (HAC 4.24)
*/
int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
int mpi_is_prime( mpi *X, unsigned char (*f_rng)(void *), void *p_rng )
{
int ret, i, j, n, s, xs;
mpi W, R, T, A, RR;
@@ -1755,7 +1755,7 @@ int mpi_is_prime( mpi *X, int (*f_rng)(void *), void *p_rng )
p = (unsigned char *) A.p;
for( j = 0; j < A.n * ciL; j++ )
*p++ = (unsigned char) f_rng( p_rng );
*p++ = f_rng( p_rng );
j = mpi_msb( &A ) - mpi_msb( &W );
MPI_CHK( mpi_shift_r( &A, j + 1 ) );
@@ -1809,7 +1809,7 @@ cleanup:
* Prime number generation
*/
int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
int (*f_rng)(void *), void *p_rng )
unsigned char (*f_rng)(void *), void *p_rng )
{
int ret, k, n;
unsigned char *p;
@@ -1827,7 +1827,7 @@ int mpi_gen_prime( mpi *X, int nbits, int dh_flag,
p = (unsigned char *) X->p;
for( k = 0; k < X->n * ciL; k++ )
*p++ = (unsigned char) f_rng( p_rng );
*p++ = f_rng( p_rng );
k = mpi_msb( X );
if( k < nbits ) MPI_CHK( mpi_shift_l( X, nbits - k ) );

View File

@@ -58,7 +58,7 @@ void rsa_init( rsa_context *ctx,
* Generate an RSA keypair
*/
int rsa_gen_key( rsa_context *ctx,
int (*f_rng)(void *),
unsigned char (*f_rng)(void *),
void *p_rng,
int nbits, int exponent )
{
@@ -101,6 +101,7 @@ int rsa_gen_key( rsa_context *ctx,
}
while( mpi_cmp_int( &G, 1 ) != 0 );
#if 0
/*
* D = E^-1 mod ((P-1)*(Q-1))
* DP = D mod (P - 1)
@@ -111,6 +112,7 @@ int rsa_gen_key( rsa_context *ctx,
MPI_CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) );
MPI_CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) );
MPI_CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) );
#endif
ctx->len = ( mpi_msb( &ctx->N ) + 7 ) >> 3;
@@ -129,6 +131,7 @@ cleanup:
#endif
#if 0
/*
* Check a public RSA key
*/
@@ -197,6 +200,7 @@ cleanup:
mpi_free( &G, &I, &H, &Q1, &P1, &DE, &PQ, &G2, &L1, &L2, NULL );
return( POLARSSL_ERR_RSA_KEY_CHECK_FAILED | ret );
}
#endif
/*
* Do an RSA public key operation
@@ -295,7 +299,7 @@ cleanup:
* Add the message padding, then do an RSA operation
*/
int rsa_pkcs1_encrypt( rsa_context *ctx,
int (*f_rng)(void *),
unsigned char (*f_rng)(void *),
void *p_rng,
int mode, int ilen,
const unsigned char *input,
@@ -323,7 +327,7 @@ int rsa_pkcs1_encrypt( rsa_context *ctx,
int rng_dl = 100;
do {
*p = (unsigned char) f_rng( p_rng );
*p = f_rng( p_rng );
} while( *p == 0 && --rng_dl );
// Check if RNG failed to generate data

View File

@@ -2,7 +2,6 @@
PROJECT = regnual
SRCS = regnual.c usb_lld.c sys.c
OBJS = regnual.o usb_lld.o sys.o
LDSCRIPT= regnual.ld
@@ -23,7 +22,7 @@ MCFLAGS= -mcpu=$(MCU) -mfix-cortex-m3-ldrd
DEFS = -DFREE_STANDING
CFLAGS = -O2 -g
CFLAGS += $(CWARN) -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
CFLAGS += $(CWARN) -I . -I ../src -fno-common $(MCFLAGS) $(TOPT) $(DEFS)
LDFLAGS = -T$(LDSCRIPT) -nostartfiles $(MCFLAGS) $(TOPT)
@@ -38,8 +37,8 @@ regnual.hex: regnual.elf
$(OBJCOPY) -Obinary regnual.elf regnual.bin
$(OBJCOPY) -Oihex regnual.elf regnual.hex
usb_lld.c: ../src/usb_lld.c
cp -p ../src/usb_lld.c .
usb_lld.o: ../src/usb_lld.c
$(CC) $(CFLAGS) -c -o usb_lld.o ../src/usb_lld.c
regnual.elf: $(OBJS) $(LDSCRIPT)
$(CC) $(LDFLAGS) -o regnual.elf $(OBJS)
@@ -48,4 +47,3 @@ clean:
-rm -f $(OBJS) regnual.elf regnual.hex regnual.bin
distclean: clean
-rm -f usb_lld.c

View File

@@ -175,7 +175,7 @@ DLIBS =
#
# List all user C define here, like -D_DEBUG=1
UDEFS =
UDEFS = @KEYGEN_SUPPORT@
# Define ASM defines here
UADEFS =

View File

@@ -1,7 +1,7 @@
/*
* ac.c -- Check access condition
*
* Copyright (C) 2010 Free Software Initiative of Japan
* Copyright (C) 2010, 2012 Free Software Initiative of Japan
* Author: NIIBE Yutaka <gniibe@fsij.org>
*
* This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -24,9 +24,7 @@
#include "config.h"
#include "ch.h"
#include "gnuk.h"
#include "polarssl/config.h"
#include "polarssl/sha1.h"
#include "sha256.h"
uint8_t volatile auth_status; /* Initialized to AC_NONE_AUTHORIZED */
@@ -89,7 +87,7 @@ verify_user_0 (uint8_t access, const uint8_t *pw, int buf_len, int pw_len_known,
}
success_one_step:
sha1 (pw, pw_len, keystring);
s2k (BY_USER, pw, pw_len, keystring);
if (access == AC_PSO_CDS_AUTHORIZED)
{
r1 = gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, keystring);
@@ -161,28 +159,27 @@ static void
calc_md (int count, const uint8_t *salt, const uint8_t *pw, int pw_len,
uint8_t md[KEYSTRING_MD_SIZE])
{
sha1_context sha1_ctx;
sha256_context sha256_ctx;
sha1_starts (&sha1_ctx);
sha256_start (&sha256_ctx);
while (count > pw_len + 8)
{
sha1_update (&sha1_ctx, salt, 8);
sha1_update (&sha1_ctx, pw, pw_len);
sha256_update (&sha256_ctx, salt, 8);
sha256_update (&sha256_ctx, pw, pw_len);
count -= pw_len + 8;
}
if (count <= 8)
sha1_update (&sha1_ctx, salt, count);
sha256_update (&sha256_ctx, salt, count);
else
{
sha1_update (&sha1_ctx, salt, 8);
sha256_update (&sha256_ctx, salt, 8);
count -= 8;
sha1_update (&sha1_ctx, pw, count);
sha256_update (&sha256_ctx, pw, count);
}
sha1_finish (&sha1_ctx, md);
memset (&sha1_ctx, 0, sizeof (sha1_ctx));
sha256_finish (&sha256_ctx, md);
}
uint8_t keystring_md_pw3[KEYSTRING_MD_SIZE];
@@ -205,7 +202,7 @@ verify_admin_0 (const uint8_t *pw, int buf_len, int pw_len_known)
return 0;
pw_len = pw3_keystring[0];
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len < buf_len)
if ((pw_len_known >= 0 && pw_len_known != pw_len) || pw_len > buf_len)
goto failure;
salt = &pw3_keystring[1];
@@ -283,7 +280,7 @@ verify_admin (const uint8_t *pw, int pw_len)
if (r <= 0)
return r;
sha1 (pw, pw_len, keystring_md_pw3);
s2k (admin_authorized, pw, pw_len, keystring_md_pw3);
auth_status |= AC_ADMIN_AUTHORIZED;
return 1;
}
@@ -293,6 +290,7 @@ ac_reset_admin (void)
{
memset (keystring_md_pw3, 0, KEYSTRING_MD_SIZE);
auth_status &= ~AC_ADMIN_AUTHORIZED;
admin_authorized = 0;
}
void
@@ -303,4 +301,5 @@ ac_fini (void)
gpg_do_clear_prvkey (GPG_KEY_FOR_DECRYPTION);
gpg_do_clear_prvkey (GPG_KEY_FOR_AUTHENTICATION);
auth_status = AC_NONE_AUTHORIZED;
admin_authorized = 0;
}

View File

@@ -1,7 +1,7 @@
/*
* call-rsa.c -- Glue code between RSA computation and OpenPGP card protocol
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 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.
@@ -47,10 +47,12 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = KEY_CONTENT_LEN;
mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_lset (&rsa_ctx.E, 0x10001);
mpi_read_binary (&rsa_ctx.P, &kd->data[0], rsa_ctx.len / 2);
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2], rsa_ctx.len / 2);
#if 0 /* Using CRT, we don't use N */
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
#endif
mpi_sub_int (&P1, &rsa_ctx.P, 1);
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
mpi_mul_mpi (&H, &P1, &Q1);
@@ -61,17 +63,6 @@ rsa_sign (const uint8_t *raw_message, uint8_t *output, int msg_len,
mpi_free (&P1, &Q1, &H, NULL);
DEBUG_INFO ("RSA sign...");
#if 0
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
DEBUG_INFO ("ok...");
else
{
DEBUG_INFO ("failed.\r\n");
DEBUG_SHORT (r);
rsa_free (&rsa_ctx);
return r;
}
#endif
r = rsa_pkcs1_sign (&rsa_ctx, RSA_PRIVATE, SIG_RSA_RAW,
msg_len, raw_message, temp);
@@ -138,11 +129,13 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
rsa_ctx.len = msg_len;
DEBUG_WORD (msg_len);
mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_lset (&rsa_ctx.E, 0x10001);
mpi_read_binary (&rsa_ctx.P, &kd->data[0], KEY_CONTENT_LEN / 2);
mpi_read_binary (&rsa_ctx.Q, &kd->data[KEY_CONTENT_LEN/2],
KEY_CONTENT_LEN / 2);
#if 0 /* Using CRT, we don't use N */
mpi_mul_mpi (&rsa_ctx.N, &rsa_ctx.P, &rsa_ctx.Q);
#endif
mpi_sub_int (&P1, &rsa_ctx.P, 1);
mpi_sub_int (&Q1, &rsa_ctx.Q, 1);
mpi_mul_mpi (&H, &P1, &Q1);
@@ -153,18 +146,6 @@ rsa_decrypt (const uint8_t *input, uint8_t *output, int msg_len,
mpi_free (&P1, &Q1, &H, NULL);
DEBUG_INFO ("RSA decrypt ...");
#if 0
/* This consume some memory */
if ((r = rsa_check_privkey (&rsa_ctx)) == 0)
DEBUG_INFO ("ok...");
else
{
DEBUG_INFO ("failed.\r\n");
DEBUG_SHORT (r);
rsa_free (&rsa_ctx);
return r;
}
#endif
r = rsa_pkcs1_decrypt (&rsa_ctx, RSA_PRIVATE, &output_len,
input, output, MAX_RES_APDU_DATA_SIZE);
@@ -191,12 +172,12 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
rsa_ctx.len = KEY_CONTENT_LEN;
mpi_read_string (&rsa_ctx.E, 16, "10001");
mpi_lset (&rsa_ctx.E, 0x10001);
mpi_read_binary (&rsa_ctx.N, pubkey, KEY_CONTENT_LEN);
DEBUG_INFO ("RSA verify...");
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA1, 20, hash, sig);
r = rsa_pkcs1_verify (&rsa_ctx, RSA_PUBLIC, SIG_RSA_SHA256, 32, hash, sig);
rsa_free (&rsa_ctx);
if (r < 0)
@@ -211,3 +192,37 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig)
return 0;
}
}
#define RSA_EXPONENT 0x10001
#ifdef KEYGEN_SUPPORT
const uint8_t *
rsa_genkey (void)
{
int r;
uint8_t index = 0;
uint8_t *p_q_modulus = (uint8_t *)malloc (KEY_CONTENT_LEN*2);
uint8_t *p = p_q_modulus;
uint8_t *q = p_q_modulus + KEY_CONTENT_LEN/2;
uint8_t *modulus = p_q_modulus + KEY_CONTENT_LEN;
if (p_q_modulus == NULL)
return NULL;
rsa_init (&rsa_ctx, RSA_PKCS_V15, 0);
r = rsa_gen_key (&rsa_ctx, random_byte, &index,
KEY_CONTENT_LEN * 8, RSA_EXPONENT);
if (r < 0)
{
free (p_q_modulus);
rsa_free (&rsa_ctx);
return NULL;
}
mpi_write_binary (&rsa_ctx.P, p, KEY_CONTENT_LEN/2);
mpi_write_binary (&rsa_ctx.Q, q, KEY_CONTENT_LEN/2);
mpi_write_binary (&rsa_ctx.N, modulus, KEY_CONTENT_LEN);
rsa_free (&rsa_ctx);
return p_q_modulus;
}
#endif

30
src/configure vendored
View File

@@ -28,6 +28,7 @@ with_dfu=default
debug=no
pinpad=no
certdo=no
keygen=no
# Process each option
for option; do
@@ -49,8 +50,6 @@ for option; do
debug=yes ;;
--disable-debug)
debug=no ;;
--enable-pinpad)
pinpad=yes ;;
--enable-pinpad=*)
pinpad=$optarg ;;
--disable-pinpad)
@@ -59,6 +58,10 @@ for option; do
certdo=yes ;;
--disable-certdo)
certdo=no ;;
--enable-keygen)
keygen=yes ;;
--disable-keygen)
keygen=no ;;
--with-dfu)
with_dfu=yes ;;
--without-dfu)
@@ -90,9 +93,10 @@ Configuration:
STBEE
FST_01
--enable-debug debug with virtual COM port [no]
--enable-pinpad={dnd,cir,dial}
--enable-pinpad={cir,dial}
PIN entry support [no]
--enable-certdo support CERT.3 data object [no]
--enable-keygen support key generation [no]
--with-dfu build image for DFU [<target specific>]
EOF
exit 0
@@ -169,12 +173,6 @@ if test "$pinpad" = "no"; then
PINPAD_DEFINE="#undef PINPAD_SUPPORT"
PINPAD_MORE_DEFINE=""
echo "PIN pad option disabled"
elif test "$pinpad" = "yes"; then
pinpad=dnd
PINPAD_MAKE_OPTION="ENABLE_PINPAD=dnd"
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
PINPAD_MORE_DEFINE="#define PINPAD_DND_SUPPORT 1"
echo "PIN pad option enabled (dnd)"
else
PINPAD_MAKE_OPTION="ENABLE_PINPAD=$pinpad"
PINPAD_DEFINE="#define PINPAD_SUPPORT 1"
@@ -188,11 +186,20 @@ if test "$certdo" = "yes"; then
echo "CERT.3 Data Object is supported"
else
CERTDO_DEFINE="#undef CERTDO_SUPPORT"
echo "CERT.3 Data Object is not supported"
echo "CERT.3 Data Object is NOT supported"
fi
# --enable-keygen option
if test "$keygen" = "yes"; then
KEYGEN_SUPPORT="-DKEYGEN_SUPPORT"
echo "Key generation on device is supported"
else
KEYGEN_SUPPORT=""
echo "Key generation on device is NOT supported"
fi
REVISION=`git describe --dirty="-modified"`
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo"
CONFIG="$target:dfu=$with_dfu:debug=$debug:pinpad=$pinpad:certdo=$certdo:keygen=$keygen"
if !(IFS=" "
while read VIDPID VERSION PRODUCT VENDOR; do
@@ -242,6 +249,7 @@ fi
sed -e "s%@BOARD_DIR@%$BOARD_DIR%" \
-e "s%@DEBUG_MAKE_OPTION@%$DEBUG_MAKE_OPTION%" \
-e "s%@PINPAD_MAKE_OPTION@%$PINPAD_MAKE_OPTION%" \
-e "s%@KEYGEN_SUPPORT@%$KEYGEN_SUPPORT%" \
< Makefile.in > Makefile
if test "$certdo" = "yes"; then
sed -e "/^@CERTDO_SUPPORT_START@$/ d" -e "/^@CERTDO_SUPPORT_END@$/ d" \

View File

@@ -1,6 +1,6 @@
CRYPTDIR = ../polarssl-0.14.0
CRYPTSRCDIR = $(CRYPTDIR)/library
CRYPTINCDIR = $(CRYPTDIR)/include
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c $(CRYPTSRCDIR)/sha1.c \
CRYPTSRC = $(CRYPTSRCDIR)/bignum.c $(CRYPTSRCDIR)/rsa.c \
$(CRYPTSRCDIR)/aes.c \
call-rsa.c
sha256.c call-rsa.c

View File

@@ -46,7 +46,7 @@
* .data
* _bss_start
* .bss
* _end
* _end
* <alignment to page>
* ch_certificate_startp
* <2048 bytes>
@@ -55,9 +55,11 @@
* _keystore_pool
* 1.5-KiB Key store (512-byte (p, q and N) key-store * 3)
*/
#define KEY_SIZE 512 /* P, Q and N */
#define FLASH_DATA_POOL_HEADER_SIZE 2
#define FLASH_DATA_POOL_SIZE (FLASH_PAGE_SIZE*2)
#define FLASH_KEYSTORE_SIZE (512*3)
#define FLASH_KEYSTORE_SIZE (KEY_SIZE*3)
static const uint8_t *data_pool;
extern uint8_t _keystore_pool;
@@ -96,7 +98,7 @@ flash_init (void)
/* Seek empty keystore */
p = &_keystore_pool;
while (*p != 0xff || *(p+1) != 0xff)
p += 512;
p += KEY_SIZE;
keystore = p;
@@ -279,7 +281,7 @@ flash_key_alloc (void)
if ((k - &_keystore_pool) >= FLASH_KEYSTORE_SIZE)
return NULL;
keystore += 512;
keystore += KEY_SIZE;
return k;
}

View File

@@ -120,6 +120,7 @@ extern void gpg_data_copy (const uint8_t *p);
extern void gpg_do_get_data (uint16_t tag, int with_tag);
extern void gpg_do_put_data (uint16_t tag, const uint8_t *data, int len);
extern void gpg_do_public_key (uint8_t kk_byte);
extern void gpg_do_keygen (uint8_t kk_byte);
extern const uint8_t *gpg_get_firmware_update_key (uint8_t keyno);
@@ -134,6 +135,8 @@ extern const uint8_t *flash_init (void);
extern void flash_do_release (const uint8_t *);
extern const uint8_t *flash_do_write (uint8_t nr, const uint8_t *data, int len);
extern uint8_t *flash_key_alloc (void);
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data,
const uint8_t *modulus);
extern void flash_keystore_release (void);
extern void flash_set_data_pool_last (const uint8_t *p);
extern void flash_clear_halfword (uint32_t addr);
@@ -155,9 +158,9 @@ extern int flash_write_binary (uint8_t file_id, const uint8_t *data, uint16_t le
extern uint8_t ch_certificate_start;
extern uint8_t random_bits_start;
#define KEY_MAGIC_LEN 8
#define KEY_CONTENT_LEN 256 /* p and q */
#define GNUK_MAGIC "Gnuk KEY"
#define INITIAL_VECTOR_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
/* encrypted data content */
struct key_data {
@@ -166,22 +169,21 @@ struct key_data {
struct key_data_internal {
uint8_t data[KEY_CONTENT_LEN]; /* p and q */
uint32_t check;
uint32_t random;
char magic[KEY_MAGIC_LEN];
uint8_t checksum[DATA_ENCRYPTION_KEY_SIZE];
};
#define ADDITIONAL_DATA_SIZE 16
#define DATA_ENCRYPTION_KEY_SIZE 16
struct prvkey_data {
const uint8_t *key_addr;
/*
* CRM: [C]heck, [R]andom, and [M]agic in struct key_data_internal
*
* IV: Initial Vector
*/
uint8_t crm_encrypted[ADDITIONAL_DATA_SIZE];
uint8_t iv[INITIAL_VECTOR_SIZE];
/*
* DEK: Data Encryption Key
* Checksum
*/
uint8_t checksum_encrypted[DATA_ENCRYPTION_KEY_SIZE];
/*
* DEK (Data Encryption Key) encrypted
*/
uint8_t dek_encrypted_1[DATA_ENCRYPTION_KEY_SIZE]; /* For user */
uint8_t dek_encrypted_2[DATA_ENCRYPTION_KEY_SIZE]; /* For resetcode */
@@ -192,12 +194,14 @@ struct prvkey_data {
#define BY_RESETCODE 2
#define BY_ADMIN 3
extern int flash_key_write (uint8_t *key_addr, const uint8_t *key_data, const uint8_t *modulus);
extern void s2k (int who, const unsigned char *input, unsigned int ilen,
unsigned char output[32]);
#define KEYSTRING_PASSLEN_SIZE 1
#define KEYSTRING_SALT_SIZE 8 /* optional */
#define KEYSTRING_ITER_SIZE 1 /* optional */
#define KEYSTRING_MD_SIZE 20
#define KEYSTRING_MD_SIZE 32
#define KEYSTRING_SIZE_PW1 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
#define KEYSTRING_SIZE_RC (KEYSTRING_PASSLEN_SIZE+KEYSTRING_MD_SIZE)
#define KEYSTRING_SIZE_PW3 (KEYSTRING_PASSLEN_SIZE+KEYSTRING_SALT_SIZE \
@@ -234,6 +238,7 @@ extern void modulus_free (const uint8_t *);
extern int rsa_decrypt (const uint8_t *, uint8_t *, int, struct key_data *);
extern int rsa_verify (const uint8_t *pubkey, const uint8_t *hash,
const uint8_t *signature);
extern const uint8_t *rsa_genkey (void);
extern const uint8_t *gpg_do_read_simple (uint8_t);
extern void gpg_do_write_simple (uint8_t, const uint8_t *, int);
@@ -301,7 +306,7 @@ extern uint8_t admin_authorized;
/*
* Representation of Boolean object:
* 0: No record in flash memory
* 1: 0xc?00
* 1: 0xf000
*/
#define NR_BOOL_PW1_LIFETIME 0xf0
/*
@@ -310,7 +315,7 @@ extern uint8_t admin_authorized;
/* 123-counters: Recorded in flash memory by 2-halfword (4-byte). */
/*
* Representation of 123-counters:
* 0: No record in flash memory
* 0: No record in flash memory
* 1: 0xfe?? 0xffff
* 2: 0xfe?? 0xc3c3
* 3: 0xfe?? 0x0000
@@ -327,6 +332,8 @@ extern const uint8_t *random_bytes_get (void);
extern void random_bytes_free (const uint8_t *);
/* 4-byte salt */
extern uint32_t get_salt (void);
/* iterator returning a byta at a time */
extern uint8_t random_byte (void *arg);
extern uint32_t hardclock (void);
@@ -359,13 +366,12 @@ extern void flash_do_write_internal (const uint8_t *p, int nr, const uint8_t *da
extern const uint8_t gnukStringSerial[];
#define LED_ONESHOT_SHORT ((eventmask_t)1)
#define LED_ONESHOT_LONG ((eventmask_t)2)
#define LED_TWOSHOT ((eventmask_t)4)
#define LED_STATUS_MODE ((eventmask_t)8)
#define LED_INPUT_MODE ((eventmask_t)16)
#define LED_FATAL_MODE ((eventmask_t)32)
extern Thread *main_thread;
#define LED_ONESHOT ((eventmask_t)1)
#define LED_TWOSHOTS ((eventmask_t)2)
#define LED_SHOW_STATUS ((eventmask_t)4)
#define LED_START_COMMAND ((eventmask_t)8)
#define LED_FINISH_COMMAND ((eventmask_t)16)
#define LED_FATAL ((eventmask_t)32)
extern void led_blink (int spec);
#if defined(PINPAD_SUPPORT)

View File

@@ -170,10 +170,12 @@ extern msg_t USBthread (void *arg);
/*
* main thread does 1-bit LED display output
*/
#define LED_TIMEOUT_INTERVAL MS2ST(100)
#define LED_TIMEOUT_ZERO MS2ST(50)
#define LED_TIMEOUT_ONE MS2ST(200)
#define LED_TIMEOUT_STOP MS2ST(500)
#define MAIN_TIMEOUT_INTERVAL MS2ST(5000)
#define LED_TIMEOUT_INTERVAL MS2ST(75)
#define LED_TIMEOUT_ZERO MS2ST(25)
#define LED_TIMEOUT_ONE MS2ST(100)
#define LED_TIMEOUT_STOP MS2ST(200)
#define ID_OFFSET 22
@@ -194,7 +196,7 @@ device_initialize_once (void)
for (i = 0; i < 4; i++)
{
uint8_t b = u[i];
uint8_t nibble;
uint8_t nibble;
nibble = (b >> 4);
nibble += (nibble >= 10 ? ('A' - 10) : '0');
@@ -208,95 +210,64 @@ device_initialize_once (void)
static volatile uint8_t fatal_code;
Thread *main_thread;
#define GNUK_INIT 0
#define GNUK_RUNNING 1
#define GNUK_INPUT_WAIT 2
#define GNUK_FATAL 255
/*
* 0 for initializing
* 1 for normal mode
* 2 for input waiting
* 255 for fatal
*/
static uint8_t main_mode;
static void display_interaction (void)
{
eventmask_t m;
while (1)
{
m = chEvtWaitOne (ALL_EVENTS);
set_led (1);
switch (m)
{
case LED_ONESHOT_SHORT:
chThdSleep (MS2ST (100));
break;
case LED_ONESHOT_LONG:
chThdSleep (MS2ST (400));
break;
case LED_TWOSHOT:
chThdSleep (MS2ST (50));
set_led (0);
chThdSleep (MS2ST (50));
set_led (1);
chThdSleep (MS2ST (50));
break;
case LED_STATUS_MODE:
chThdSleep (MS2ST (400));
set_led (0);
return;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
set_led (0);
return;
default:
break;
}
set_led (0);
}
}
static Thread *main_thread;
static void display_fatal_code (void)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
while (1)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
set_led (1);
if (fatal_code & 1)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if (fatal_code & 2)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL*10);
}
}
static void display_status_code (void)
static uint8_t led_inverted;
static eventmask_t emit_led (int on_time, int off_time)
{
eventmask_t m;
set_led (!led_inverted);
m = chEvtWaitOneTimeout (ALL_EVENTS, on_time);
set_led (led_inverted);
if (m) return m;
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, off_time)))
return m;
return 0;
}
static eventmask_t display_status_code (void)
{
enum icc_state icc_state;
eventmask_t m;
if (icc_state_p == NULL)
icc_state = ICC_STATE_START;
@@ -304,70 +275,47 @@ static void display_status_code (void)
icc_state = *icc_state_p;
if (icc_state == ICC_STATE_START)
{
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3);
}
return emit_led (LED_TIMEOUT_ONE, LED_TIMEOUT_STOP);
else
/* GPGthread running */
{
set_led (1);
if ((auth_status & AC_ADMIN_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_OTHER_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
if ((auth_status & AC_PSO_CDS_AUTHORIZED) != 0)
chThdSleep (LED_TIMEOUT_ONE);
else
chThdSleep (LED_TIMEOUT_ZERO);
if ((m = emit_led ((auth_status & AC_ADMIN_AUTHORIZED)?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
LED_TIMEOUT_INTERVAL)))
return m;
if ((m = emit_led ((auth_status & AC_OTHER_AUTHORIZED)?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
LED_TIMEOUT_INTERVAL)))
return m;
if ((m = emit_led ((auth_status & AC_PSO_CDS_AUTHORIZED)?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
LED_TIMEOUT_INTERVAL)))
return m;
if (icc_state == ICC_STATE_WAIT)
{
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 2);
}
else if (icc_state == ICC_STATE_RECEIVE)
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_ONE);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP);
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP * 2)))
return m;
}
else
{
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
set_led (1);
chThdSleep (LED_TIMEOUT_STOP);
set_led (0);
chThdSleep (LED_TIMEOUT_INTERVAL);
if ((m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL)))
return m;
if ((m = emit_led (icc_state == ICC_STATE_RECEIVE?
LED_TIMEOUT_ONE : LED_TIMEOUT_ZERO,
LED_TIMEOUT_STOP)))
return m;
}
return 0;
}
}
void
led_blink (int spec)
{
if (spec == 0)
chEvtSignal (main_thread, LED_ONESHOT_SHORT);
else if (spec == 1)
chEvtSignal (main_thread, LED_ONESHOT_LONG);
else
chEvtSignal (main_thread, LED_TWOSHOT);
chEvtSignal (main_thread, spec);
}
@@ -380,7 +328,7 @@ led_blink (int spec)
int
main (int argc, char *argv[])
{
int count = 0;
unsigned int count = 0;
(void)argc;
(void)argv;
@@ -417,6 +365,7 @@ main (int argc, char *argv[])
msc_init ();
#endif
while (1)
{
eventmask_t m;
@@ -424,45 +373,41 @@ main (int argc, char *argv[])
if (icc_state_p != NULL && *icc_state_p == ICC_STATE_EXEC_REQUESTED)
break;
m = chEvtWaitOneTimeout (ALL_EVENTS, MAIN_TIMEOUT_INTERVAL);
got_it:
count++;
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_INTERVAL);
switch (m)
{
case LED_STATUS_MODE:
main_mode = GNUK_RUNNING;
case LED_ONESHOT:
if ((m = emit_led (MS2ST (100), MAIN_TIMEOUT_INTERVAL))) goto got_it;
break;
case LED_FATAL_MODE:
main_mode = GNUK_FATAL;
case LED_TWOSHOTS:
if ((m = emit_led (MS2ST (50), MS2ST (50)))) goto got_it;
if ((m = emit_led (MS2ST (50), MAIN_TIMEOUT_INTERVAL))) goto got_it;
break;
case LED_INPUT_MODE:
main_mode = GNUK_INPUT_WAIT;
case LED_SHOW_STATUS:
if ((count & 0x07) != 0) continue; /* Display once for eight times */
if ((m = display_status_code ())) goto got_it;
break;
case LED_START_COMMAND:
set_led (1);
chThdSleep (MS2ST (400));
led_inverted = 1;
break;
case LED_FINISH_COMMAND:
m = chEvtWaitOneTimeout (ALL_EVENTS, LED_TIMEOUT_STOP);
led_inverted = 0;
set_led (0);
if (m)
goto got_it;
break;
default:
break;
}
switch (main_mode)
{
case GNUK_FATAL:
case LED_FATAL:
display_fatal_code ();
break;
case GNUK_INIT:
set_led (1);
chThdSleep (LED_TIMEOUT_ZERO);
set_led (0);
chThdSleep (LED_TIMEOUT_STOP * 3);
break;
case GNUK_INPUT_WAIT:
display_interaction ();
break;
case GNUK_RUNNING:
default:
display_status_code ();
if ((m = emit_led (LED_TIMEOUT_ZERO, LED_TIMEOUT_STOP)))
goto got_it;
break;
}
}
#ifdef DEBUG_MORE
if (bDeviceState == CONFIGURED && (count % 10) == 0)
@@ -500,12 +445,12 @@ main (int argc, char *argv[])
/* copy system service routines */
flash_write (FLASH_SYS_START_ADDR, &_sys, 0x1000);
/* Leave Gnuk to exec reGNUal */
/* Leave Gnuk to exec reGNUal */
(*func) (*((void (**)(void))(&_regnual_start+4)));
for (;;);
}
#else
/* Leave Gnuk to exec reGNUal */
/* Leave Gnuk to exec reGNUal */
flash_erase_all_and_exec (*((void (**)(void))(&_regnual_start+4)));
#endif
@@ -517,7 +462,7 @@ void
fatal (uint8_t code)
{
fatal_code = code;
chEvtSignal (main_thread, LED_FATAL_MODE);
chEvtSignal (main_thread, LED_FATAL);
_write ("fatal\r\n", 7);
for (;;);
}

View File

@@ -32,15 +32,15 @@ static Thread *rng_thread;
/* Total number of channels to be sampled by a single ADC operation.*/
#define ADC_GRP1_NUM_CHANNELS 2
/* Depth of the conversion buffer, channels are sampled one time each.*/
#define ADC_GRP1_BUF_DEPTH 4
/*
* ADC samples buffer.
*/
static adcsample_t samp[ADC_GRP1_NUM_CHANNELS * ADC_GRP1_BUF_DEPTH];
static void adccb (adcsample_t *buffer, size_t n);
/*

View File

@@ -1,7 +1,7 @@
/*
* openpgp-do.c -- OpenPGP card Data Objects (DO) handling
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 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.
@@ -31,7 +31,6 @@
#include "polarssl/config.h"
#include "polarssl/aes.h"
#include "polarssl/sha1.h"
#define PASSWORD_ERRORS_MAX 3 /* >= errors, it will be locked */
static const uint8_t *pw_err_counter_p[3];
@@ -163,6 +162,17 @@ gpg_write_digital_signature_counter (const uint8_t *p, uint32_t dsc)
}
}
static void
gpg_reset_digital_signature_counter (void)
{
if (digital_signature_counter != 0)
{
flash_put_data (NR_COUNTER_DS);
flash_put_data (NR_COUNTER_DS_LSB);
digital_signature_counter = 0;
}
}
void
gpg_increment_digital_signature_counter (void)
{
@@ -532,7 +542,7 @@ proc_resetting_code (const uint8_t *data, int len)
newpw_len = len;
newpw = data;
sha1 (newpw, newpw_len, new_ks);
s2k (BY_RESETCODE, newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (admin_authorized, old_ks, BY_RESETCODE, new_ks);
if (r <= -2)
@@ -561,40 +571,58 @@ proc_resetting_code (const uint8_t *data, int len)
}
static void
encrypt (const uint8_t *key_str, uint8_t *data, int len)
encrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
{
aes_context aes;
uint8_t iv[16];
uint8_t iv0[INITIAL_VECTOR_SIZE];
int iv_offset;
DEBUG_INFO ("ENC\r\n");
DEBUG_BINARY (data, len);
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
aes_setkey_enc (&aes, key, 128);
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
iv_offset = 0;
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv, data, data);
aes_crypt_cfb128 (&aes, AES_ENCRYPT, len, &iv_offset, iv0, data, data);
}
/* Signing, Decryption, and Authentication */
struct key_data kd[3];
static void
decrypt (const uint8_t *key_str, uint8_t *data, int len)
decrypt (const uint8_t *key, const uint8_t *iv, uint8_t *data, int len)
{
aes_context aes;
uint8_t iv[16];
uint8_t iv0[INITIAL_VECTOR_SIZE];
int iv_offset;
aes_setkey_enc (&aes, key_str, 128);
memset (iv, 0, 16);
aes_setkey_enc (&aes, key, 128); /* This is setkey_enc, because of CFB. */
memcpy (iv0, iv, INITIAL_VECTOR_SIZE);
iv_offset = 0;
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv, data, data);
aes_crypt_cfb128 (&aes, AES_DECRYPT, len, &iv_offset, iv0, data, data);
DEBUG_INFO ("DEC\r\n");
DEBUG_BINARY (data, len);
}
static void
encrypt_dek (const uint8_t *key_string, uint8_t *dek)
{
aes_context aes;
aes_setkey_enc (&aes, key_string, 128);
aes_crypt_ecb (&aes, AES_ENCRYPT, dek, dek);
}
static void
decrypt_dek (const uint8_t *key_string, uint8_t *dek)
{
aes_context aes;
aes_setkey_dec (&aes, key_string, 128);
aes_crypt_ecb (&aes, AES_DECRYPT, dek, dek);
}
static uint8_t
get_do_ptr_nr_for_kk (enum kind_of_key kk)
{
@@ -616,6 +644,25 @@ gpg_do_clear_prvkey (enum kind_of_key kk)
memset ((void *)&kd[kk], 0, sizeof (struct key_data));
}
static int
compute_key_data_checksum (struct key_data_internal *kdi, int check_or_calc)
{
unsigned int i;
uint32_t d[4] = { 0, 0, 0, 0 };
for (i = 0; i < KEY_CONTENT_LEN / sizeof (uint32_t); i++)
d[i&3] ^= *(uint32_t *)(&kdi->data[i*4]);
if (check_or_calc == 0) /* store */
{
memcpy (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE);
return 0;
}
else /* check */
return memcmp (kdi->checksum, d, DATA_ENCRYPTION_KEY_SIZE) == 0;
}
/*
* Return 1 on success,
* 0 if none,
@@ -626,8 +673,9 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
uint8_t *key_addr;
const uint8_t *key_addr;
uint8_t dek[DATA_ENCRYPTION_KEY_SIZE];
const uint8_t *iv;
struct key_data_internal kdi;
DEBUG_INFO ("Loading private key: ");
@@ -636,60 +684,47 @@ gpg_do_load_prvkey (enum kind_of_key kk, int who, const uint8_t *keystring)
if (do_data == NULL)
return 0;
key_addr = *(uint8_t **)&(do_data)[1];
key_addr = *(const uint8_t **)&(do_data)[1]; /* Possible unaligned access */
memcpy (kdi.data, key_addr, KEY_CONTENT_LEN);
memcpy (((uint8_t *)&kdi.check), do_data+5, ADDITIONAL_DATA_SIZE);
iv = do_data+5;
memcpy (kdi.checksum, iv + INITIAL_VECTOR_SIZE, DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, do_data+5+16*who, DATA_ENCRYPTION_KEY_SIZE);
decrypt (keystring, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (dek, do_data+5+16*(who+1), DATA_ENCRYPTION_KEY_SIZE);
decrypt_dek (keystring, dek);
decrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
if (memcmp (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN) != 0)
decrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
memset (dek, 0, DATA_ENCRYPTION_KEY_SIZE);
if (!compute_key_data_checksum (&kdi, 1))
{
DEBUG_INFO ("gpg_do_load_prvkey failed.\r\n");
return -1;
}
/* more sanity check??? */
memcpy (kd[kk].data, kdi.data, KEY_CONTENT_LEN);
DEBUG_BINARY (&kd[kk], KEY_CONTENT_LEN);
return 1;
}
static uint32_t
calc_check32 (const uint8_t *p, int len)
{
uint32_t check = 0;
uint32_t *data = (uint32_t *)p;
int i;
for (i = 0; i < len/4; i++)
check += data[i];
return check;
}
static int8_t num_prv_keys;
static int
gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
const uint8_t *keystring_admin)
const uint8_t *keystring_admin, const uint8_t *modulus)
{
uint8_t nr = get_do_ptr_nr_for_kk (kk);
const uint8_t *p;
int r;
const uint8_t *modulus;
struct prvkey_data *pd;
uint8_t *key_addr;
const uint8_t *dek;
const uint8_t *dek, *iv;
const uint8_t *do_data = do_ptr[nr - NR_DO__FIRST__];
const uint8_t *ks_pw1;
const uint8_t *ks_rc;
struct key_data_internal kdi;
#if 0
assert (key_len == KEY_CONTENT_LEN);
#endif
int modulus_allocated_here = 0;
uint8_t ks_pw1_len = 0;
uint8_t ks_rc_len = 0;
DEBUG_INFO ("Key import\r\n");
DEBUG_SHORT (key_len);
@@ -698,15 +733,23 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
/* No replace support, you need to remove it first. */
return -1;
if (key_len != KEY_CONTENT_LEN)
return -1;
pd = (struct prvkey_data *)malloc (sizeof (struct prvkey_data));
if (pd == NULL)
return -1;
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (pd);
return -1;
modulus = modulus_calc (key_data, key_len);
if (modulus == NULL)
{
free (pd);
return -1;
}
modulus_allocated_here = 1;
}
DEBUG_INFO ("Getting keystore address...\r\n");
@@ -714,7 +757,8 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
if (key_addr == NULL)
{
free (pd);
modulus_free (modulus);
if (modulus_allocated_here)
modulus_free (modulus);
return -1;
}
@@ -722,21 +766,21 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
DEBUG_WORD ((uint32_t)key_addr);
memcpy (kdi.data, key_data, KEY_CONTENT_LEN);
kdi.check = calc_check32 (key_data, KEY_CONTENT_LEN);
kdi.random = get_salt ();
memcpy (kdi.magic, GNUK_MAGIC, KEY_MAGIC_LEN);
compute_key_data_checksum (&kdi, 0);
dek = random_bytes_get (); /* 16-byte random bytes */
dek = random_bytes_get (); /* 32-byte random bytes */
iv = dek + DATA_ENCRYPTION_KEY_SIZE;
memcpy (pd->dek_encrypted_1, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_2, dek, DATA_ENCRYPTION_KEY_SIZE);
memcpy (pd->dek_encrypted_3, dek, DATA_ENCRYPTION_KEY_SIZE);
ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
ks_rc = gpg_do_read_simple (NR_DO_KEYSTRING_RC);
encrypt (dek, (uint8_t *)&kdi, sizeof (struct key_data_internal));
encrypt (dek, iv, (uint8_t *)&kdi, sizeof (struct key_data_internal));
r = flash_key_write (key_addr, kdi.data, modulus);
modulus_free (modulus);
if (modulus_allocated_here)
modulus_free (modulus);
if (r < 0)
{
@@ -746,32 +790,33 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
}
pd->key_addr = key_addr;
memcpy (pd->crm_encrypted, (uint8_t *)&kdi.check, ADDITIONAL_DATA_SIZE);
if (kk == GPG_KEY_FOR_SIGNING)
ac_reset_pso_cds ();
else
ac_reset_other ();
memcpy (pd->iv, iv, INITIAL_VECTOR_SIZE);
memcpy (pd->checksum_encrypted, kdi.checksum, DATA_ENCRYPTION_KEY_SIZE);
if (ks_pw1)
encrypt (ks_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
{
ks_pw1_len = ks_pw1[0];
encrypt_dek (ks_pw1+1, pd->dek_encrypted_1);
}
else
{
uint8_t ks123_pw1[KEYSTRING_SIZE_PW1];
uint8_t ks[KEYSTRING_MD_SIZE];
ks123_pw1[0] = strlen (OPENPGP_CARD_INITIAL_PW1);
sha1 ((uint8_t *)OPENPGP_CARD_INITIAL_PW1,
strlen (OPENPGP_CARD_INITIAL_PW1), ks123_pw1+1);
encrypt (ks123_pw1+1, pd->dek_encrypted_1, DATA_ENCRYPTION_KEY_SIZE);
s2k (BY_USER, (const uint8_t *)OPENPGP_CARD_INITIAL_PW1,
strlen (OPENPGP_CARD_INITIAL_PW1), ks);
encrypt_dek (ks, pd->dek_encrypted_1);
}
if (ks_rc)
encrypt (ks_rc+1, pd->dek_encrypted_2, DATA_ENCRYPTION_KEY_SIZE);
{
ks_rc_len = ks_rc[0];
encrypt_dek (ks_rc+1, pd->dek_encrypted_2);
}
else
memset (pd->dek_encrypted_2, 0, DATA_ENCRYPTION_KEY_SIZE);
if (keystring_admin)
encrypt (keystring_admin, pd->dek_encrypted_3, DATA_ENCRYPTION_KEY_SIZE);
encrypt_dek (keystring_admin, pd->dek_encrypted_3);
else
memset (pd->dek_encrypted_3, 0, DATA_ENCRYPTION_KEY_SIZE);
@@ -786,17 +831,11 @@ gpg_do_write_prvkey (enum kind_of_key kk, const uint8_t *key_data, int key_len,
if (++num_prv_keys == NUM_ALL_PRV_KEYS) /* All keys are registered. */
{
/* Remove contents of keystrings from DO, but length */
if (ks_pw1)
{
uint8_t ks_pw1_len = ks_pw1[0];
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
}
if (ks_pw1_len)
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, &ks_pw1_len, 1);
if (ks_rc)
{
uint8_t ks_rc_len = ks_rc[0];
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
}
if (ks_rc_len)
gpg_do_write_simple (NR_DO_KEYSTRING_RC, &ks_rc_len, 1);
}
return 0;
@@ -821,19 +860,21 @@ gpg_do_chks_prvkey (enum kind_of_key kk,
if (pd == NULL)
return -1;
memcpy (pd, &(do_data)[1], sizeof (struct prvkey_data));
dek_p = ((uint8_t *)pd) + 4 + ADDITIONAL_DATA_SIZE
+ DATA_ENCRYPTION_KEY_SIZE * (who_old - 1);
memcpy (pd, &do_data[1], sizeof (struct prvkey_data));
flash_do_release (do_data);
dek_p = ((uint8_t *)pd) + 4 + INITIAL_VECTOR_SIZE
+ DATA_ENCRYPTION_KEY_SIZE * who_old;
memcpy (dek, dek_p, DATA_ENCRYPTION_KEY_SIZE);
decrypt (old_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
encrypt (new_ks, dek, DATA_ENCRYPTION_KEY_SIZE);
decrypt_dek (old_ks, dek);
encrypt_dek (new_ks, dek);
dek_p += DATA_ENCRYPTION_KEY_SIZE * (who_new - who_old);
memcpy (dek_p, dek, DATA_ENCRYPTION_KEY_SIZE);
do_ptr[nr - NR_DO__FIRST__] = NULL;
p = flash_do_write (nr, (const uint8_t *)pd, sizeof (struct prvkey_data));
do_ptr[nr - NR_DO__FIRST__] = p;
flash_do_release (do_data);
free (pd);
if (p == NULL)
return -1;
@@ -877,11 +918,19 @@ proc_key_import (const uint8_t *data, int len)
p += 1;
if (*p == 0xb6)
kk = GPG_KEY_FOR_SIGNING;
else if (*p == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
{
kk = GPG_KEY_FOR_SIGNING;
ac_reset_pso_cds ();
gpg_reset_digital_signature_counter ();
}
else
{
if (*p == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
ac_reset_other ();
}
if (len <= 22)
{ /* Deletion of the key */
@@ -901,6 +950,11 @@ proc_key_import (const uint8_t *data, int len)
/* Delete PW1 and RC if any */
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, NULL, 0);
gpg_do_write_simple (NR_DO_KEYSTRING_RC, NULL, 0);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
}
return 1;
@@ -908,7 +962,7 @@ proc_key_import (const uint8_t *data, int len)
/* It should starts with 00 01 00 01 (E) */
/* Skip E, 4-byte */
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin);
r = gpg_do_write_prvkey (kk, &data[26], len - 26, keystring_admin, NULL);
if (r < 0)
return 0;
else
@@ -989,7 +1043,7 @@ gpg_do_table[] = {
/ sizeof (struct do_table_entry))
/*
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
* Reading data from Flash ROM, initialize DO_PTR, PW_ERR_COUNTERS, etc.
*/
void
gpg_data_scan (const uint8_t *p_start)
@@ -1039,18 +1093,18 @@ gpg_data_scan (const uint8_t *p_start)
}
else
switch (nr)
{
case NR_BOOL_PW1_LIFETIME:
pw1_lifetime_p = p - 1;
p++;
continue;
case NR_COUNTER_123:
p++;
if (second_byte <= PW_ERR_PW3)
pw_err_counter_p[second_byte] = p;
p += 2;
break;
}
{
case NR_BOOL_PW1_LIFETIME:
pw1_lifetime_p = p - 1;
p++;
continue;
case NR_COUNTER_123:
p++;
if (second_byte <= PW_ERR_PW3)
pw_err_counter_p[second_byte] = p;
p += 2;
break;
}
}
}
@@ -1237,8 +1291,8 @@ copy_do (const struct do_table_entry *do_p, int with_tag)
}
case DO_PROC_READWRITE:
{
int (*rw_func)(uint16_t, int, uint8_t *, int, int)
= (int (*)(uint16_t, int, uint8_t *, int, int))do_p->obj;
int (*rw_func)(uint16_t, int, const uint8_t *, int, int)
= (int (*)(uint16_t, int, const uint8_t *, int, int))do_p->obj;
return rw_func (do_p->tag, with_tag, NULL, 0, 0);
}
@@ -1339,6 +1393,7 @@ gpg_do_put_data (uint16_t tag, const uint8_t *data, int len)
GPG_MEMORY_FAILURE ();
else
{
*do_data_p = NULL;
*do_data_p = flash_do_write (nr, data, len);
if (*do_data_p)
GPG_SUCCESS ();
@@ -1453,6 +1508,7 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
if (data != NULL)
{
*do_data_p = NULL;
*do_data_p = flash_do_write (nr, data, size);
if (*do_data_p == NULL)
flash_warning ("DO WRITE ERROR");
@@ -1460,3 +1516,78 @@ gpg_do_write_simple (uint8_t nr, const uint8_t *data, int size)
else
*do_data_p = NULL;
}
#ifdef KEYGEN_SUPPORT
void
gpg_do_keygen (uint8_t kk_byte)
{
enum kind_of_key kk;
const uint8_t *keystring_admin;
const uint8_t *p_q_modulus;
const uint8_t *p_q;
const uint8_t *modulus;
int r;
DEBUG_INFO ("Keygen\r\n");
DEBUG_BYTE (kk_byte);
if (kk_byte == 0xb6)
kk = GPG_KEY_FOR_SIGNING;
else if (kk_byte == 0xb8)
kk = GPG_KEY_FOR_DECRYPTION;
else /* 0xa4 */
kk = GPG_KEY_FOR_AUTHENTICATION;
if (admin_authorized == BY_ADMIN)
keystring_admin = keystring_md_pw3;
else
keystring_admin = NULL;
p_q_modulus = rsa_genkey ();
if (p_q_modulus == NULL)
{
GPG_MEMORY_FAILURE ();
return;
}
p_q = p_q_modulus;
modulus = p_q_modulus + KEY_CONTENT_LEN;
r = gpg_do_write_prvkey (kk, p_q, KEY_CONTENT_LEN,
keystring_admin, modulus);
free ((uint8_t *)p_q_modulus);
if (r < 0)
{
GPG_ERROR ();
return;
}
DEBUG_INFO ("Calling gpg_do_public_key...\r\n");
if (kk == GPG_KEY_FOR_SIGNING)
{
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
uint8_t keystring[KEYSTRING_MD_SIZE];
const uint8_t *ks;
/* GnuPG expects it's ready for signing. */
/* Don't call ac_reset_pso_cds here, but load the private key */
if (ks_pw1)
ks = ks_pw1+1;
else
{
const uint8_t * pw = (const uint8_t *)OPENPGP_CARD_INITIAL_PW1;
s2k (BY_USER, pw, strlen (OPENPGP_CARD_INITIAL_PW1), keystring);
ks = keystring;
}
gpg_do_load_prvkey (GPG_KEY_FOR_SIGNING, BY_USER, ks);
}
else
ac_reset_other ();
gpg_do_public_key (kk_byte);
}
#endif

View File

@@ -27,8 +27,7 @@
#include "gnuk.h"
#include "sys.h"
#include "openpgp.h"
#include "polarssl/config.h"
#include "polarssl/sha1.h"
#include "sha256.h"
#define CLS(a) a.cmd_apdu_head[0]
#define INS(a) a.cmd_apdu_head[1]
@@ -51,7 +50,7 @@
#define INS_PUT_DATA 0xda
#define INS_PUT_DATA_ODD 0xdb /* For key import */
#define CHALLENGE_LEN 16
#define CHALLENGE_LEN 32
static const uint8_t *challenge; /* Random bytes */
static const uint8_t
@@ -108,7 +107,7 @@ gpg_fini (void)
}
#if defined(PINPAD_SUPPORT)
/*
/*
* Let user input PIN string.
* Return length of the string.
* The string itself is in PIN_INPUT_BUFFER.
@@ -118,9 +117,9 @@ get_pinpad_input (int msg_code)
{
int r;
chEvtSignal (main_thread, LED_INPUT_MODE);
led_blink (LED_START_COMMAND);
r = pinpad_getline (msg_code, MS2ST (8000));
chEvtSignal (main_thread, LED_STATUS_MODE);
led_blink (LED_FINISH_COMMAND);
return r;
}
#endif
@@ -221,10 +220,10 @@ cmd_change_password (void)
uint8_t p1 = P1 (apdu); /* 0: change (old+new), 1: exchange (new) */
uint8_t p2 = P2 (apdu);
int len;
const uint8_t *pw;
const uint8_t *newpw;
uint8_t *pw, *newpw;
int pw_len, newpw_len;
int who = p2 - 0x80;
int who_old;
int r;
DEBUG_INFO ("Change PW\r\n");
@@ -244,6 +243,7 @@ cmd_change_password (void)
const uint8_t *ks_pw1 = gpg_do_read_simple (NR_DO_KEYSTRING_PW1);
pw_len = verify_user_0 (AC_PSO_CDS_AUTHORIZED, pw, len, -1, ks_pw1);
who_old = who;
if (pw_len < 0)
{
@@ -283,15 +283,23 @@ cmd_change_password (void)
{
newpw = pw + pw_len;
newpw_len = len - pw_len;
gpg_set_pw3 (newpw, newpw_len);
if (newpw_len == 0 && admin_authorized == BY_ADMIN)
{
newpw_len = strlen (OPENPGP_CARD_INITIAL_PW3);
memcpy (newpw, OPENPGP_CARD_INITIAL_PW3, newpw_len);
gpg_do_write_simple (NR_DO_KEYSTRING_PW3, NULL, 0);
}
else
gpg_set_pw3 (newpw, newpw_len);
who_old = admin_authorized;
}
}
sha1 (pw, pw_len, old_ks);
sha1 (newpw, newpw_len, new_ks);
s2k (who_old, pw, pw_len, old_ks);
s2k (who, newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (who, old_ks, who, new_ks);
r = gpg_change_keystring (who_old, old_ks, who, new_ks);
if (r <= -2)
{
DEBUG_INFO ("memory error.\r\n");
@@ -307,6 +315,8 @@ cmd_change_password (void)
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, KEYSTRING_SIZE_PW1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
DEBUG_INFO ("Changed DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS ();
}
@@ -315,6 +325,8 @@ cmd_change_password (void)
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
DEBUG_INFO ("Changed length of DO_KEYSTRING_PW1.\r\n");
GPG_SUCCESS ();
}
@@ -326,6 +338,29 @@ cmd_change_password (void)
}
}
#define USER_S2K_MAGIC "\xffUSER\r\n"
#define RESETCODE_S2K_MAGIC "\xffRESET\r\n"
void
s2k (int who, const unsigned char *input, unsigned int ilen,
unsigned char output[32])
{
sha256_context ctx;
sha256_start (&ctx);
sha256_update (&ctx, input, ilen);
if (who == BY_USER)
sha256_update (&ctx, (unsigned char *)USER_S2K_MAGIC,
sizeof (USER_S2K_MAGIC));
else if (who == BY_RESETCODE)
sha256_update (&ctx, (unsigned char *)RESETCODE_S2K_MAGIC,
sizeof (RESETCODE_S2K_MAGIC));
/* Not add any for BY_ADMIN */
sha256_finish (&ctx, output);
}
static void
cmd_reset_user_password (void)
{
@@ -366,8 +401,8 @@ cmd_reset_user_password (void)
pw_len = ks_rc[0];
newpw = pw + pw_len;
newpw_len = len - pw_len;
sha1 (pw, pw_len, old_ks);
sha1 (newpw, newpw_len, new_ks);
s2k (BY_RESETCODE, pw, pw_len, old_ks);
s2k (BY_USER, newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (BY_RESETCODE, old_ks, BY_USER, new_ks);
if (r <= -2)
@@ -391,6 +426,8 @@ cmd_reset_user_password (void)
KEYSTRING_SIZE_PW1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
gpg_pw_reset_err_counter (PW_ERR_RC);
gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS ();
@@ -398,8 +435,11 @@ cmd_reset_user_password (void)
else
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
gpg_pw_reset_err_counter (PW_ERR_RC);
gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS ();
@@ -418,7 +458,7 @@ cmd_reset_user_password (void)
newpw_len = len;
newpw = pw;
sha1 (newpw, newpw_len, new_ks);
s2k (BY_USER, newpw, newpw_len, new_ks);
new_ks0[0] = newpw_len;
r = gpg_change_keystring (admin_authorized, old_ks, BY_USER, new_ks);
if (r <= -2)
@@ -438,14 +478,19 @@ cmd_reset_user_password (void)
KEYSTRING_SIZE_PW1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS ();
}
else
{
DEBUG_INFO ("done.\r\n");
gpg_do_write_simple (NR_DO_KEYSTRING_PW1, new_ks0, 1);
ac_reset_pso_cds ();
ac_reset_other ();
if (admin_authorized == BY_USER)
ac_reset_admin ();
gpg_pw_reset_err_counter (PW_ERR_PW1);
GPG_SUCCESS ();
}
@@ -480,12 +525,15 @@ cmd_pgp_gakp (void)
/* Get public key */
gpg_do_public_key (apdu.cmd_apdu_data[0]);
else
{ /* Generate key pair */
{
if (!ac_check_status (AC_ADMIN_AUTHORIZED))
GPG_SECURITY_FAILURE ();
/* XXX: Not yet supported */
GPG_ERROR ();
#ifdef KEYGEN_SUPPORT
/* Generate key pair */
gpg_do_keygen (apdu.cmd_apdu_data[0]);
#else
GPG_FUNCTION_NOT_SUPPORTED ();
#endif
}
}
@@ -728,10 +776,15 @@ cmd_pso (void)
/* Skip padding 0x00 */
len--;
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
&kd[GPG_KEY_FOR_DECRYPTION]);
if (r < 0)
GPG_ERROR ();
if (len != KEY_CONTENT_LEN)
GPG_CONDITION_NOT_SATISFIED ();
else
{
r = rsa_decrypt (apdu.cmd_apdu_data+1, res_APDU, len,
&kd[GPG_KEY_FOR_DECRYPTION]);
if (r < 0)
GPG_ERROR ();
}
}
else
{
@@ -745,6 +798,8 @@ cmd_pso (void)
DEBUG_INFO ("PSO done.\r\n");
}
#define MAX_DIGEST_INFO_LEN 102 /* 40% */
static void
cmd_internal_authenticate (void)
{
@@ -764,6 +819,13 @@ cmd_internal_authenticate (void)
return;
}
if (len > MAX_DIGEST_INFO_LEN)
{
DEBUG_INFO ("input is too long.");
GPG_CONDITION_NOT_SATISFIED ();
return;
}
r = rsa_sign (apdu.cmd_apdu_data, res_APDU, len,
&kd[GPG_KEY_FOR_AUTHENTICATION]);
if (r < 0)
@@ -901,9 +963,9 @@ cmd_external_authenticate (void)
{
const uint8_t *pubkey;
const uint8_t *signature = apdu.cmd_apdu_data;
uint8_t *hash = apdu.cmd_apdu_data + 256;
int len = apdu.cmd_apdu_data_len;
uint8_t keyno = P2 (apdu);
int r;
DEBUG_INFO (" - EXTERNAL AUTHENTICATE\r\n");
@@ -921,13 +983,12 @@ cmd_external_authenticate (void)
GPG_CONDITION_NOT_SATISFIED ();
return;
}
memcpy (hash, unique_device_id (), 4);
memcpy (hash+4, challenge, CHALLENGE_LEN);
r = rsa_verify (pubkey, challenge, signature);
random_bytes_free (challenge);
challenge = NULL;
if (rsa_verify (pubkey, hash, signature) < 0)
if (r < 0)
{
GPG_SECURITY_FAILURE ();
return;
@@ -947,9 +1008,8 @@ cmd_get_challenge (void)
random_bytes_free (challenge);
challenge = random_bytes_get ();
memcpy (res_APDU, unique_device_id (), 4);
memcpy (res_APDU+4, challenge, CHALLENGE_LEN);
res_APDU_size = CHALLENGE_LEN + 4;
memcpy (res_APDU, challenge, CHALLENGE_LEN);
res_APDU_size = CHALLENGE_LEN;
GPG_SUCCESS ();
DEBUG_INFO ("GET CHALLENGE done.\r\n");
}
@@ -1104,7 +1164,9 @@ GPGthread (void *arg)
else if (m == EV_NOP)
continue;
led_blink (LED_START_COMMAND);
process_command_apdu ();
led_blink (LED_FINISH_COMMAND);
done:
chEvtSignal (icc_thread, EV_EXEC_FINISHED);
}

View File

@@ -595,7 +595,7 @@ cir_getchar (systime_t timeout)
static Thread *pin_thread;
/*
/*
* Let user input PIN string.
* Return length of the string.
* The string itself is in PIN_INPUT_BUFFER.
@@ -620,7 +620,7 @@ pinpad_getline (int msg_code, systime_t timeout)
if (ch_is_backspace (ch))
{
led_blink (2);
led_blink (LED_TWOSHOTS);
if (pin_input_len > 0)
pin_input_len--;
}
@@ -628,7 +628,7 @@ pinpad_getline (int msg_code, systime_t timeout)
break;
else if (pin_input_len < MAX_PIN_CHARS)
{
led_blink (0);
led_blink (LED_ONESHOT);
pin_input_buffer[pin_input_len++] = ch;
}
}

View File

@@ -51,7 +51,7 @@ uint8_t pin_input_len;
#define OFF '\x00'
#define ENTER '\x0a'
static struct led_pattern { uint8_t c, v; } led_pattern[] =
static struct led_pattern { uint8_t c, v; } led_pattern[] =
{
/* char : dp a b c d e f g */
{ ENTER, 0xf8 }, /* |- : 1 1 1 1 1 0 0 0 (enter) */

View File

@@ -41,7 +41,7 @@ uint8_t pin_input_len;
static Thread *pin_thread;
/*
/*
* Let user input PIN string.
* Return length of the string.
* The string itself is in PIN_INPUT_BUFFER.
@@ -71,7 +71,7 @@ pinpad_getline (int msg_code, systime_t timeout)
msg = chThdSelf ()->p_u.rdymsg;
chSysUnlock ();
led_blink (0);
led_blink (LED_ONESHOT);
if (msg != 0)
break;
}

View File

@@ -1,7 +1,7 @@
/*
* random.c -- get random bytes
*
* Copyright (C) 2010, 2011 Free Software Initiative of Japan
* Copyright (C) 2010, 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.
@@ -26,7 +26,7 @@
#include "gnuk.h"
#include "neug.h"
#define RANDOM_BYTES_LENGTH 16
#define RANDOM_BYTES_LENGTH 32
static uint32_t random_word[RANDOM_BYTES_LENGTH/sizeof (uint32_t)];
void
@@ -43,7 +43,7 @@ random_init (void)
}
/*
* Return pointer to random 16-byte
* Return pointer to random 32-byte
*/
const uint8_t *
random_bytes_get (void)
@@ -53,12 +53,13 @@ random_bytes_get (void)
}
/*
* Free pointer to random 16-byte
* Free pointer to random 32-byte
*/
void
random_bytes_free (const uint8_t *p)
{
(void)p;
memset (random_word, 0, RANDOM_BYTES_LENGTH);
neug_flush ();
}
@@ -70,3 +71,32 @@ get_salt (void)
{
return neug_get (NEUG_KICK_FILLING);
}
#ifdef KEYGEN_SUPPORT
/*
* Random byte iterator
*/
uint8_t
random_byte (void *arg)
{
uint8_t *index_p = (uint8_t *)arg;
uint8_t index = *index_p;
uint8_t *p = ((uint8_t *)random_word) + index;
uint8_t v;
neug_wait_full ();
v = *p;
if (++index >= RANDOM_BYTES_LENGTH)
{
index = 0;
neug_flush ();
}
*index_p = index;
return v;
}
#endif

222
src/sha256.c Normal file
View File

@@ -0,0 +1,222 @@
/*
* sha256.c -- Compute SHA-256 hash
*
* Just for little endian architecture.
*
* Code taken from:
* http://gladman.plushost.co.uk/oldsite/cryptography_technology/sha/index.php
*
* File names are sha2.c, sha2.h, brg_types.h, brg_endian.h
* in the archive sha2-07-01-07.zip.
*
* Code is modified in the style of PolarSSL API.
*
* See original copyright notice below.
*/
/*
---------------------------------------------------------------------------
Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved.
LICENSE TERMS
The free distribution and use of this software in both source and binary
form is allowed (with or without changes) provided that:
1. distributions of this source code include the above copyright
notice, this list of conditions and the following disclaimer;
2. distributions in binary form include the above copyright
notice, this list of conditions and the following disclaimer
in the documentation and/or other associated materials;
3. the copyright holder's name is not used to endorse products
built using this software without specific written permission.
ALTERNATIVELY, provided that this notice is retained in full, this product
may be distributed under the terms of the GNU General Public License (GPL),
in which case the provisions of the GPL apply INSTEAD OF those given above.
DISCLAIMER
This software is provided 'as is' with no explicit or implied warranties
in respect of its properties, including, but not limited to, correctness
and/or fitness for purpose.
---------------------------------------------------------------------------
Issue Date: 01/08/2005
*/
#include <string.h>
#include <stdlib.h>
#include "sha256.h"
#define SHA256_DIGEST_SIZE 32
#define SHA256_BLOCK_SIZE 64
#define SHA256_MASK (SHA256_BLOCK_SIZE - 1)
static void bswap32_buf (uint32_t *p, int n)
{
while (n--)
p[n] = __builtin_bswap32 (p[n]); /* bswap32 is GCC extention */
}
#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n)))
#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y))))
/* round transforms for SHA256 compression functions */
#define vf(n,i) v[(n - i) & 7]
#define hf(i) (p[i & 15] += \
g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15]))
#define v_cycle(i,j) \
vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \
+ s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \
vf(3,i) += vf(7,i); \
vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i))
#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22))
#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25))
#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3))
#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10))
#define k_0 k256
const uint32_t k256[64] = {
0X428A2F98, 0X71374491, 0XB5C0FBCF, 0XE9B5DBA5,
0X3956C25B, 0X59F111F1, 0X923F82A4, 0XAB1C5ED5,
0XD807AA98, 0X12835B01, 0X243185BE, 0X550C7DC3,
0X72BE5D74, 0X80DEB1FE, 0X9BDC06A7, 0XC19BF174,
0XE49B69C1, 0XEFBE4786, 0X0FC19DC6, 0X240CA1CC,
0X2DE92C6F, 0X4A7484AA, 0X5CB0A9DC, 0X76F988DA,
0X983E5152, 0XA831C66D, 0XB00327C8, 0XBF597FC7,
0XC6E00BF3, 0XD5A79147, 0X06CA6351, 0X14292967,
0X27B70A85, 0X2E1B2138, 0X4D2C6DFC, 0X53380D13,
0X650A7354, 0X766A0ABB, 0X81C2C92E, 0X92722C85,
0XA2BFE8A1, 0XA81A664B, 0XC24B8B70, 0XC76C51A3,
0XD192E819, 0XD6990624, 0XF40E3585, 0X106AA070,
0X19A4C116, 0X1E376C08, 0X2748774C, 0X34B0BCB5,
0X391C0CB3, 0X4ED8AA4A, 0X5B9CCA4F, 0X682E6FF3,
0X748F82EE, 0X78A5636F, 0X84C87814, 0X8CC70208,
0X90BEFFFA, 0XA4506CEB, 0XBEF9A3F7, 0XC67178F2,
};
void
sha256_process (sha256_context *ctx)
{
uint32_t i;
uint32_t *p = ctx->wbuf;
uint32_t v[8];
memcpy (v, ctx->state, 8 * sizeof (uint32_t));
for (i = 0; i < 64; i += 16)
{
v_cycle ( 0, i);
v_cycle ( 1, i);
v_cycle ( 2, i);
v_cycle ( 3, i);
v_cycle ( 4, i);
v_cycle ( 5, i);
v_cycle ( 6, i);
v_cycle ( 7, i);
v_cycle ( 8, i);
v_cycle ( 9, i);
v_cycle (10, i);
v_cycle (11, i);
v_cycle (12, i);
v_cycle (13, i);
v_cycle (14, i);
v_cycle (15, i);
}
ctx->state[0] += v[0];
ctx->state[1] += v[1];
ctx->state[2] += v[2];
ctx->state[3] += v[3];
ctx->state[4] += v[4];
ctx->state[5] += v[5];
ctx->state[6] += v[6];
ctx->state[7] += v[7];
}
void
sha256_update (sha256_context *ctx, const unsigned char *input,
unsigned int ilen)
{
uint32_t left = (ctx->total[0] & SHA256_MASK);
uint32_t fill = SHA256_BLOCK_SIZE - left;
ctx->total[0] += ilen;
if (ctx->total[0] < ilen)
ctx->total[1]++;
while (ilen >= fill)
{
memcpy (((unsigned char*)ctx->wbuf) + left, input, fill);
bswap32_buf (ctx->wbuf, SHA256_BLOCK_SIZE >> 2);
sha256_process (ctx);
input += fill;
ilen -= fill;
left = 0;
fill = SHA256_BLOCK_SIZE;
}
memcpy (((unsigned char*)ctx->wbuf) + left, input, ilen);
}
void
sha256_finish (sha256_context *ctx, unsigned char output[32])
{
uint32_t last = (ctx->total[0] & SHA256_MASK);
bswap32_buf (ctx->wbuf, (last + 3) >> 2);
ctx->wbuf[last >> 2] &= 0xffffff80 << (8 * (~last & 3));
ctx->wbuf[last >> 2] |= 0x00000080 << (8 * (~last & 3));
if (last > SHA256_BLOCK_SIZE - 9)
{
if (last < 60)
ctx->wbuf[15] = 0;
sha256_process (ctx);
last = 0;
}
else
last = (last >> 2) + 1;
while (last < 14)
ctx->wbuf[last++] = 0;
ctx->wbuf[14] = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
ctx->wbuf[15] = ctx->total[0] << 3;
sha256_process (ctx);
bswap32_buf (ctx->state, SHA256_DIGEST_SIZE >> 2);
memcpy (output, ctx->state, SHA256_DIGEST_SIZE);
memset (ctx, 0, sizeof (sha256_context));
}
const uint32_t initial_state[8] =
{
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
};
void
sha256_start (sha256_context *ctx)
{
ctx->total[0] = ctx->total[1] = 0;
memcpy (ctx->state, initial_state, 8 * sizeof(uint32_t));
}
void
sha256 (const unsigned char *input, unsigned int ilen,
unsigned char output[32])
{
sha256_context ctx;
sha256_start (&ctx);
sha256_update (&ctx, input, ilen);
sha256_finish (&ctx, output);
}

14
src/sha256.h Normal file
View File

@@ -0,0 +1,14 @@
typedef struct
{
uint32_t total[2];
uint32_t state[8];
uint32_t wbuf[16];
} sha256_context;
extern void sha256 (const unsigned char *input, unsigned int ilen,
unsigned char output[32]);
extern void sha256_start (sha256_context *ctx);
extern void sha256_finish (sha256_context *ctx, unsigned char output[32]);
extern void sha256_update (sha256_context *ctx, const unsigned char *input,
unsigned int ilen);
extern void sha256_process (sha256_context *ctx);

View File

@@ -116,7 +116,7 @@ flash_erase_page (uint32_t addr)
if (status == 0)
{
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = addr;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
status = flash_wait_for_last_operation (FLASH_ERASE_TIMEOUT);

View File

@@ -803,6 +803,7 @@ icc_send_status (struct ccid *c)
c->epi->tx_done = 1;
usb_lld_write (c->epi->ep_num, icc_reply, ICC_MSG_HEADER_SIZE);
led_blink (LED_SHOW_STATUS);
#ifdef DEBUG_MORE
DEBUG_INFO ("St\r\n");
#endif
@@ -1260,6 +1261,7 @@ icc_handle_timeout (struct ccid *c)
{
case ICC_STATE_EXECUTE:
icc_send_data_block (c, ICC_CMD_STATUS_TIMEEXT);
led_blink (LED_ONESHOT);
break;
default:
break;

View File

@@ -372,7 +372,7 @@ void msc_handle_command (void)
msc_send_result (buf, 12);
return;
case SCSI_START_STOP_UNIT:
if (CBW.CBWCB[4] == 0x00 /* stop */
if (CBW.CBWCB[4] == 0x00 /* stop */
|| CBW.CBWCB[4] == 0x02 /* eject */ || CBW.CBWCB[4] == 0x03 /* close */)
{
msc_scsi_stop (CBW.CBWCB[4]);
@@ -380,7 +380,7 @@ void msc_handle_command (void)
contingent_allegiance = 1;
keep_contingent_allegiance = 1;
}
/* CBW.CBWCB[4] == 0x01 *//* start */
/* CBW.CBWCB[4] == 0x01 *//* start */
goto success;
case SCSI_TEST_UNIT_READY:
if (contingent_allegiance)

View File

@@ -381,7 +381,6 @@ static int gnuk_usb_event (uint8_t event_type, uint16_t value)
for (i = 0; i < NUM_INTERFACES; i++)
gnuk_setup_endpoints_for_interface (i, 0);
bDeviceState = CONFIGURED;
chEvtSignalI (main_thread, LED_STATUS_MODE);
}
else if (current_conf != value)
{

View File

@@ -258,11 +258,11 @@ static const uint8_t gnukStringLangID[] = {
#include "usb-strings.c.inc"
const uint8_t gnukStringSerial[] = {
18*2+2, /* bLength */
17*2+2, /* bLength */
USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
/* FSIJ-0.19 */
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
'0', 0, '.', 0, '1', 0, '9', 0, /* Version number of Gnuk */
/* FSIJ-1.0 */
'F', 0, 'S', 0, 'I', 0, 'J', 0, '-', 0,
'1', 0, '.', 0, '0', 0, /* Version number of Gnuk */
'-', 0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,

View File

@@ -852,11 +852,11 @@ static void handle_setup0 (void)
if (USB_SETUP_GET (ctrl_p->bmRequestType))
{
uint32_t len = ctrl_p->wLength;
/* Restrict the data length to be the one host asks for */
if (data_p->len > len)
data_p->len = len;
if ((data_p->len % USB_MAX_PACKET_SIZE) == 0)
data_p->require_zlp = TRUE;
else
@@ -871,7 +871,7 @@ static void handle_setup0 (void)
st103_set_tx_count (ENDP0, 0);
st103_ep_set_rxtx_status (ENDP0, EP_RX_STALL, EP_TX_VALID);
}
else
else
{
dev_p->state = OUT_DATA;
st103_ep_set_rx_status (ENDP0, EP_RX_VALID);

20
test/README Normal file
View File

@@ -0,0 +1,20 @@
This is a functionality test suite for Gnuk.
You need python-nose, python-freshen as well as python-usb.
Besides, python-crypto is needed when you use generate_keys.py to
update contents of *.key.
Type:
$ nosetests --with-freshen
or
$ nosetests -v --with-freshen
to run the test suite.
To skip tests for key generation, add an option "--tag ~keygen". To
stop running tests after the first error or failure, add "--stop" option.

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 data should match: \x30\x00\x00\x00[\x00\x08]\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,56 @@
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
Scenario: setup data object Finger print sig
Given a fingerprint of OPENPGP.1 key
And put the data to c7
Then it should get success
Scenario: setup data object Finger print dec
Given a fingerprint of OPENPGP.2 key
And put the data to c8
Then it should get success
Scenario: setup data object Finger print aut
Given a fingerprint of OPENPGP.3 key
And put the data to c9
Then it should get success
Scenario: setup data object keygeneration data/time sig
Given a timestamp of OPENPGP.1 key
And put the data to ce
Then it should get success
Scenario: setup data object keygeneration data/time dec
Given a timestamp of OPENPGP.2 key
And put the data to cf
Then it should get success
Scenario: setup data object keygeneration data/time aut
Given a timestamp of OPENPGP.3 key
And put the data to d0
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,71 @@
Feature: change pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: change PW1
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: setup reset code again (in admin-full 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-full 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: change PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase"
Then it should get success
Scenario: verify PW3 (admin-full mode)
Given cmd_verify with 3 and "another admin pass phrase"
Then it should get success
Scenario: reset pass phrase by admin (in admin-full mode)
Given cmd_reset_retry_counter with 2 and "new 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: change PW1
Given cmd_change_reference_data with 1 and "new user pass phraseanother 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
Scenario: change PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "another admin 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

View File

@@ -0,0 +1,31 @@
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: data object ds counter
When requesting ds counter: 93
Then you should get: \x00\x00\x02

View File

@@ -0,0 +1,16 @@
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

View File

@@ -0,0 +1,40 @@
@keygen
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,32 @@
@keygen
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-full 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: setup reset code (in admin-full 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-full mode)
Given cmd_reset_retry_counter with 0 and "example 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,37 @@
@keygen
Feature: key generation
In order to use a token
A token should have keys
Scenario: generate OPENPGP.1 key (sign)
When generating a key of OPENPGP.1
And put the first data to c7
And put the second data to ce
Then it should get success
Scenario: generate OPENPGP.2 key (decrypt)
When generating a key of OPENPGP.2
And put the first data to c8
And put the second data to cf
Then it should get success
Scenario: generate OPENPGP.3 key (authentication)
When generating a key of OPENPGP.3
And put the first data to c9
And put the second data to d0
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "GnuPG assumes that PW1 keeps valid after keygen."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: verify PW1 (1) after keygen
Given cmd_verify with 1 and "another user pass phrase"
Then it should get success
Scenario: verify PW1 (2) after keygen
Given cmd_verify with 2 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,71 @@
Feature: change pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: change PW1
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: setup reset code again (in admin-full mode)
Given cmd_put_data with d3 and "example reset code 111"
Then it should get success
Scenario: reset pass phrase by reset code (in admin-full mode)
Given cmd_reset_retry_counter with 0 and "example reset code 111new 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: change PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "admin pass phraseanother admin pass phrase"
Then it should get success
Scenario: verify PW3 (admin-full mode)
Given cmd_verify with 3 and "another admin pass phrase"
Then it should get success
Scenario: reset pass phrase by admin (in admin-full mode)
Given cmd_reset_retry_counter with 2 and "new 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: change PW1
Given cmd_change_reference_data with 1 and "new user pass phraseanother 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
Scenario: change PW3 (admin-full mode)
Given cmd_change_reference_data with 3 and "another admin 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

View File

@@ -0,0 +1,36 @@
@keygen
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: data object ds counter
When requesting ds counter: 93
Then data should match: \x00\x00(\x02|\x03)

View File

@@ -0,0 +1,19 @@
@keygen
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

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

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 data should match: \x30\x00\x00\x00[\x00\x08]\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,55 @@
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: change PW1
Given cmd_change_reference_data with 1 and "new user pass phraseanother 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
Scenario: verify PW3 (admin-less mode) again
Given cmd_verify with 3 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,56 @@
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
Scenario: setup data object Finger print sig
Given a fingerprint of OPENPGP.1 key
And put the data to c7
Then it should get success
Scenario: setup data object Finger print dec
Given a fingerprint of OPENPGP.2 key
And put the data to c8
Then it should get success
Scenario: setup data object Finger print aut
Given a fingerprint of OPENPGP.3 key
And put the data to c9
Then it should get success
Scenario: setup data object keygeneration data/time sig
Given a timestamp of OPENPGP.1 key
And put the data to ce
Then it should get success
Scenario: setup data object keygeneration data/time dec
Given a timestamp of OPENPGP.2 key
And put the data to cf
Then it should get success
Scenario: setup data object keygeneration data/time aut
Given a timestamp of OPENPGP.3 key
And put the data to d0
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,51 @@
Feature: change pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: change PW1 (in admin-less mode)
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: setup reset code again (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: change PW1
Given cmd_change_reference_data with 1 and "new user pass phraseanother 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
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,31 @@
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: data object ds counter
When requesting ds counter: 93
Then you should get: \x00\x00\x02

View File

@@ -0,0 +1,16 @@
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

View File

@@ -0,0 +1,44 @@
@keygen
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: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "12345678"
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,40 @@
@keygen
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 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
Scenario: verify PW3 (admin-less mode) again
Given cmd_verify with 3 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,37 @@
@keygen
Feature: key generation
In order to use a token
A token should have keys
Scenario: generate OPENPGP.1 key (sign)
When generating a key of OPENPGP.1
And put the first data to c7
And put the second data to ce
Then it should get success
Scenario: generate OPENPGP.2 key (decrypt)
When generating a key of OPENPGP.2
And put the first data to c8
And put the second data to cf
Then it should get success
Scenario: generate OPENPGP.3 key (authentication)
When generating a key of OPENPGP.3
And put the first data to c9
And put the second data to d0
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "GnuPG assumes that PW1 keeps valid after keygen."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: verify PW1 (1) after keygen
Given cmd_verify with 1 and "another user pass phrase"
Then it should get success
Scenario: verify PW1 (2) after keygen
Given cmd_verify with 2 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,67 @@
Feature: change pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: change PW1
Given cmd_change_reference_data with 1 and "another user pass phrasePASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "PASSPHRASE SHOULD BE LONG"
Then it should get success
Scenario: setup reset code again (in admin-less mode)
Given cmd_put_data with d3 and "example reset code 111"
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 111new 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)
Given cmd_verify with 3 and "new user pass phrase"
Then it should get success
Scenario: reset pass phrase by admin (in admin-less mode)
Given cmd_reset_retry_counter with 2 and "new 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: change PW1
Given cmd_change_reference_data with 1 and "new user pass phraseanother 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
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "another user pass phrase"
Then it should get success

View File

@@ -0,0 +1,36 @@
@keygen
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: data object ds counter
When requesting ds counter: 93
Then data should match: \x00\x00(\x02|\x03)

View File

@@ -0,0 +1,19 @@
@keygen
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

View File

@@ -0,0 +1,43 @@
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: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "12345678"
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: confirm factory setting pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "12345678"
Then it should get success

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 data should match: \x30\x00\x00\x00[\x00\x08]\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,15 @@
Feature: check pass phrase
In order to conform OpenPGP card 2.0 specification
A token should support pass phrase: PW1, PW3 and reset code
Scenario: verify PW1 (1)
Given cmd_verify with 1 and "123456"
Then it should get success
Scenario: verify PW1 (2)
Given cmd_verify with 2 and "123456"
Then it should get success
Scenario: verify PW3
Given cmd_verify with 3 and "12345678"
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,56 @@
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
Scenario: setup data object Finger print sig
Given a fingerprint of OPENPGP.1 key
And put the data to c7
Then it should get success
Scenario: setup data object Finger print dec
Given a fingerprint of OPENPGP.2 key
And put the data to c8
Then it should get success
Scenario: setup data object Finger print aut
Given a fingerprint of OPENPGP.3 key
And put the data to c9
Then it should get success
Scenario: setup data object keygeneration data/time sig
Given a timestamp of OPENPGP.1 key
And put the data to ce
Then it should get success
Scenario: setup data object keygeneration data/time dec
Given a timestamp of OPENPGP.2 key
And put the data to cf
Then it should get success
Scenario: setup data object keygeneration data/time aut
Given a timestamp of OPENPGP.3 key
And put the data to d0
Then it should get success
Scenario: verify PW1 (1) again
Given cmd_verify with 1 and "123456"
Then it should get success
Scenario: verify PW1 (2) again
Given cmd_verify with 2 and "123456"
Then it should get success

View File

@@ -0,0 +1,31 @@
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token compute digital signature
And compute digital signature on host with RSA key pair 0
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And let a token authenticate
And compute digital signature on host with RSA key pair 2
Then results should be same
Scenario: data object ds counter
When requesting ds counter: 93
Then you should get: \x00\x00\x02

View File

@@ -0,0 +1,16 @@
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And encrypt it on host with RSA key pair 1
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

View File

@@ -0,0 +1,48 @@
@keygen
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
Scenario: verify PW1
Given cmd_verify with 1 and "123456"
Then it should get success
Scenario: verify PW2
Given cmd_verify with 2 and "123456"
Then it should get success

View File

@@ -0,0 +1,37 @@
@keygen
Feature: key generation
In order to use a token
A token should have keys
Scenario: generate OPENPGP.1 key (sign)
When generating a key of OPENPGP.1
And put the first data to c7
And put the second data to ce
Then it should get success
Scenario: generate OPENPGP.2 key (decrypt)
When generating a key of OPENPGP.2
And put the first data to c8
And put the second data to cf
Then it should get success
Scenario: generate OPENPGP.3 key (authentication)
When generating a key of OPENPGP.3
And put the first data to c9
And put the second data to d0
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key
Given a message "GnuPG assumes that PW1 keeps valid after keygen."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: verify PW1 (1) after keygen
Given cmd_verify with 1 and "123456"
Then it should get success
Scenario: verify PW1 (2) after keygen
Given cmd_verify with 2 and "123456"
Then it should get success

View File

@@ -0,0 +1,36 @@
@keygen
Feature: compute digital signature
In order to use a token
A token should compute digital signature properly
Scenario: compute digital signature by OPENPGP.1 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.1 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.1
And let a token compute digital signature
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (1)
Given a message "This is a test message."
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: compute digital signature by OPENPGP.3 key (2)
Given a message "This is another test message.\nMultiple lines.\n"
And a public key from token for OPENPGP.3
And let a token authenticate
And verify signature
Then it should get success
Scenario: data object ds counter
When requesting ds counter: 93
Then data should match: \x00\x00(\x02|\x03)

View File

@@ -0,0 +1,19 @@
@keygen
Feature: decryption
In order to use a token
A token should decrypt encrypted data
Scenario: decrypt by OPENPGP.2 key (1)
Given a plain text "This is a test message."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text
Scenario: decrypt by OPENPGP.2 key (2)
Given a plain text "RSA decryption is as easy as pie."
And a public key from token for OPENPGP.2
And encrypt it on host
And let a token decrypt encrypted data
Then decrypted data should be same as a plain text

View File

@@ -0,0 +1,43 @@
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: verify PW3 (admin-less mode)
Given cmd_verify with 3 and "12345678"
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

Some files were not shown because too many files have changed in this diff Show More