| Index: chrome/browser/resources/cryptotoken/gnubby-u2f.js
|
| diff --git a/chrome/browser/resources/cryptotoken/gnubby-u2f.js b/chrome/browser/resources/cryptotoken/gnubby-u2f.js
|
| index 653b957d01175acdafa007f8471eea9742a6df47..39a73d6a8a75e4d108149811b61fa7483ff59d47 100644
|
| --- a/chrome/browser/resources/cryptotoken/gnubby-u2f.js
|
| +++ b/chrome/browser/resources/cryptotoken/gnubby-u2f.js
|
| @@ -7,7 +7,6 @@
|
| */
|
| 'use strict';
|
|
|
| -// Commands and flags of the Gnubby applet at
|
| /** Enroll */
|
| usbGnubby.U2F_ENROLL = 0x01;
|
| /** Request signature */
|
| @@ -28,6 +27,12 @@ usbGnubby.P1_TUP_TESTONLY = 0x04;
|
| /** Attest with device key */
|
| usbGnubby.P1_INDIVIDUAL_KEY = 0x80;
|
|
|
| +// Version values
|
| +/** V1 of the applet. */
|
| +usbGnubby.U2F_V1 = 'U2F_V1';
|
| +/** V2 of the applet. */
|
| +usbGnubby.U2F_V2 = 'U2F_V2';
|
| +
|
| /** Perform enrollment
|
| * @param {ArrayBuffer|Uint8Array} challenge Enrollment challenge
|
| * @param {ArrayBuffer|Uint8Array} appIdHash Hashed application id
|
| @@ -63,33 +68,51 @@ usbGnubby.prototype.enroll = function(challenge, appIdHash, cb) {
|
| */
|
| usbGnubby.prototype.sign = function(challengeHash, appIdHash, keyHandle, cb,
|
| opt_nowink) {
|
| - var apdu = new Uint8Array(
|
| - [0x00,
|
| - usbGnubby.U2F_SIGN,
|
| - usbGnubby.P1_TUP_REQUIRED | usbGnubby.P1_TUP_CONSUME,
|
| - 0x00, 0x00, 0x00,
|
| - challengeHash.length + appIdHash.length + keyHandle.length]);
|
| - if (opt_nowink) {
|
| - // A signature request that does not want winking.
|
| - // These are used during enroll to figure out whether a gnubby was already
|
| - // enrolled.
|
| - // Tell applet to not actually produce a signature, even
|
| - // if already touched.
|
| - apdu[2] |= usbGnubby.P1_TUP_TESTONLY;
|
| - }
|
| - var u8 = new Uint8Array(apdu.length + challengeHash.length +
|
| - appIdHash.length + keyHandle.length + 2);
|
| - for (var i = 0; i < apdu.length; ++i) u8[i] = apdu[i];
|
| - for (var i = 0; i < challengeHash.length; ++i) u8[i + apdu.length] =
|
| - challengeHash[i];
|
| - for (var i = 0; i < appIdHash.length; ++i) {
|
| - u8[i + apdu.length + challengeHash.length] = appIdHash[i];
|
| - }
|
| - for (var i = 0; i < keyHandle.length; ++i) {
|
| - u8[i + apdu.length + challengeHash.length + appIdHash.length] =
|
| - keyHandle[i];
|
| - }
|
| - this.apduReply_(u8.buffer, cb, opt_nowink);
|
| + var self = this;
|
| + // The sign command's format is ever-so-slightly different between V1 and V2,
|
| + // so get this gnubby's version prior to sending it.
|
| + this.version(function(rc, opt_data) {
|
| + if (rc) {
|
| + cb(rc);
|
| + return;
|
| + }
|
| + var version = UTIL_BytesToString(new Uint8Array(opt_data || []));
|
| + var apduDataLen =
|
| + challengeHash.length + appIdHash.length + keyHandle.length;
|
| + if (version != usbGnubby.U2F_V1) {
|
| + // The V2 sign command includes a length byte for the key handle.
|
| + apduDataLen++;
|
| + }
|
| + var apdu = new Uint8Array(
|
| + [0x00,
|
| + usbGnubby.U2F_SIGN,
|
| + usbGnubby.P1_TUP_REQUIRED | usbGnubby.P1_TUP_CONSUME,
|
| + 0x00, 0x00, 0x00,
|
| + apduDataLen]);
|
| + if (opt_nowink) {
|
| + // A signature request that does not want winking.
|
| + // These are used during enroll to figure out whether a gnubby was already
|
| + // enrolled.
|
| + // Tell applet to not actually produce a signature, even
|
| + // if already touched.
|
| + apdu[2] |= usbGnubby.P1_TUP_TESTONLY;
|
| + }
|
| + var u8 = new Uint8Array(apdu.length + apduDataLen + 2);
|
| + for (var i = 0; i < apdu.length; ++i) u8[i] = apdu[i];
|
| + for (var i = 0; i < challengeHash.length; ++i) u8[i + apdu.length] =
|
| + challengeHash[i];
|
| + for (var i = 0; i < appIdHash.length; ++i) {
|
| + u8[i + apdu.length + challengeHash.length] = appIdHash[i];
|
| + }
|
| + var keyHandleOffset = apdu.length + challengeHash.length + appIdHash.length;
|
| + if (version != usbGnubby.U2F_V1) {
|
| + u8[keyHandleOffset++] = keyHandle.length;
|
| + }
|
| + for (var i = 0; i < keyHandle.length; ++i) {
|
| + u8[i + keyHandleOffset] = keyHandle[i];
|
| + }
|
| + self.apduReply_(u8.buffer, cb, opt_nowink);
|
| + });
|
| };
|
|
|
| /** Request version information
|
| @@ -97,14 +120,23 @@ usbGnubby.prototype.sign = function(challengeHash, appIdHash, keyHandle, cb,
|
| */
|
| usbGnubby.prototype.version = function(cb) {
|
| if (!cb) cb = usbGnubby.defaultCallback;
|
| + if (this.version_) {
|
| + cb(-llGnubby.OK, this.version_);
|
| + return;
|
| + }
|
| + var self = this;
|
| var apdu = new Uint8Array([0x00, usbGnubby.U2F_VERSION, 0x00, 0x00, 0x00,
|
| 0x00, 0x00, 0x00, 0x00]);
|
| this.apduReply_(apdu.buffer, function(rc, data) {
|
| if (rc == 0x6d00) {
|
| // Command not implemented. Pretend this is v1.
|
| - var v1 = new Uint8Array(UTIL_StringToBytes('U2F_V1'));
|
| + var v1 = new Uint8Array(UTIL_StringToBytes(usbGnubby.U2F_V1));
|
| + self.version_ = v1.buffer;
|
| cb(-llGnubby.OK, v1.buffer);
|
| } else {
|
| + if (!rc) {
|
| + self.version_ = data;
|
| + }
|
| cb(rc, data);
|
| }
|
| });
|
|
|