external authenticate incompatible change to SHA256
authorNIIBE Yutaka <gniibe@fsij.org>
Sat, 16 Jun 2012 05:33:22 +0000 (14:33 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Sat, 16 Jun 2012 05:33:22 +0000 (14:33 +0900)
ChangeLog
NEWS
doc/firmware-update
src/call-rsa.c
src/openpgp.c
tool/gnuk_upgrade.py

index da8f277..93848bd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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.
diff --git a/NEWS b/NEWS
index 21b3f0b..c1c8e4f 100644 (file)
--- 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).
 
index 19b0442..52ff93f 100644 (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.
 -- 
index 13fa819..5ea7854 100644 (file)
@@ -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)
index 43c089c..89b218b 100644 (file)
@@ -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");
 }
index b03cdef..278278d 100755 (executable)
@@ -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:])