diff --git a/ChangeLog b/ChangeLog index da8f277..93848bd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2012-06-16 Niibe Yutaka + + 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 * src/random.c (random_bytes_free): Clear out random bytes. diff --git a/NEWS b/NEWS index 21b3f0b..c1c8e4f 100644 --- a/NEWS +++ b/NEWS @@ -5,14 +5,19 @@ Gnuk NEWS - User visible changes Released 2012-XX-XX, by NIIBE Yutaka ** Key generation feature added -Finally, key generation is supported. Note that it is very slow. It -will take a few minutes (or more) to generate two or three keys, when -you are unlucky. +Finally, key generation is supported. Note that it may be very slow. +It will 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). diff --git a/doc/firmware-update b/doc/firmware-update index 19b0442..52ff93f 100644 --- a/doc/firmware-update +++ b/doc/firmware-update @@ -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. -- diff --git a/src/call-rsa.c b/src/call-rsa.c index 13fa819..5ea7854 100644 --- a/src/call-rsa.c +++ b/src/call-rsa.c @@ -196,7 +196,7 @@ rsa_verify (const uint8_t *pubkey, const uint8_t *hash, const uint8_t *sig) 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) diff --git a/src/openpgp.c b/src/openpgp.c index 43c089c..89b218b 100644 --- a/src/openpgp.c +++ b/src/openpgp.c @@ -50,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 @@ -938,9 +938,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"); @@ -958,13 +958,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; @@ -984,9 +983,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"); } diff --git a/tool/gnuk_upgrade.py b/tool/gnuk_upgrade.py index b03cdef..278278d 100755 --- a/tool/gnuk_upgrade.py +++ b/tool/gnuk_upgrade.py @@ -389,11 +389,13 @@ def to_string(t): from subprocess import check_output -def gpg_sign(keygrip, hash): +SHA256_OID_PREFIX="3031300d060960864801650304020105000420" + +def gpg_sign(hash): result = check_output(["gpg-connect-agent", - "SIGKEY %s" % keygrip, - "SETHASH --hash=sha1 %s" % hash, - "PKSIGN", "/bye"]) + "SCD SETDATA " + SHA256_OID_PREFIX + hash, + "SCD PKAUTH OPENPGP.3", + "/bye"]) signed = "" while True: i = result.find('%') @@ -405,8 +407,8 @@ def gpg_sign(keygrip, hash): signed += chr(int(hex_str,16)) result = result[i+3:] - pos = signed.index("D (7:sig-val(3:rsa(1:s256:") + 26 - signed = signed[pos:-7] + pos = signed.index("D ") + 2 + signed = signed[pos:-4] # \nOK\n if len(signed) != 256: raise ValueError, binascii.hexlify(signed) return signed @@ -418,7 +420,7 @@ def crc32(bytestr): crc = binascii.crc32(bytestr) return UNSIGNED(crc) -def main(keygrip, data_regnual, data_upgrade): +def main(data_regnual, data_upgrade): l = len(data_regnual) if (l & 0x03) != 0: data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0)) @@ -440,7 +442,7 @@ def main(keygrip, data_regnual, data_upgrade): icc.icc_power_on() icc.cmd_select_openpgp() challenge = icc.cmd_get_challenge() - signed = gpg_sign(keygrip, binascii.hexlify(to_string(challenge))) + signed = gpg_sign(binascii.hexlify(to_string(challenge))) icc.cmd_external_authenticate(signed) icc.stop_gnuk() mem_info = icc.mem_info() @@ -477,9 +479,8 @@ def main(keygrip, data_regnual, data_upgrade): if __name__ == '__main__': - keygrip = sys.argv[1] - filename_regnual = sys.argv[2] - filename_upgrade = sys.argv[3] + filename_regnual = sys.argv[1] + filename_upgrade = sys.argv[2] f = open(filename_regnual) data_regnual = f.read() f.close() @@ -488,4 +489,4 @@ if __name__ == '__main__': data_upgrade = f.read() f.close() print "%s: %d" % (filename_upgrade, len(data_upgrade)) - main(keygrip, data_regnual, data_upgrade[4096:]) + main(data_regnual, data_upgrade[4096:])