15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Copyright 2014 The Chromium Authors. All rights reserved. 25c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Use of this source code is governed by a BSD-style license that can be 35c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// found in the LICENSE file. 45c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 55c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @fileoverview Implements an enroll handler using USB gnubbies. 75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 85c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu'use strict'; 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {!EnrollHelperRequest} request The enroll request. 125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @constructor 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @implements {RequestHandler} 145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)function UsbEnrollHandler(request) { 166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** @private {!EnrollHelperRequest} */ 176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.request_ = request; 185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** @private {Array.<Gnubby>} */ 205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.waitingForTouchGnubbies_ = []; 215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.closed_ = false; 245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu /** @private {boolean} */ 255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notified_ = false; 265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu} 275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * Default timeout value in case the caller never provides a valid timeout. 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @const 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */ 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.DEFAULT_TIMEOUT_MILLIS = 30 * 1000; 33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/** 356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {RequestHandlerCallback} cb Called back with the result of the 366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * request, and an optional source for the result. 376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @return {boolean} Whether this handler could be run. 385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.run = function(cb) { 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var timeoutMillis = 416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.request_.timeoutSeconds ? 426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.request_.timeoutSeconds * 1000 : 436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) UsbEnrollHandler.DEFAULT_TIMEOUT_MILLIS; 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch /** @private {Countdown} */ 456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.timer_ = DEVICE_FACTORY_REGISTRY.getCountdownFactory().createTimer( 466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) timeoutMillis); 476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.enrollChallenges = this.request_.enrollChallenges; 486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) /** @private {RequestHandlerCallback} */ 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.cb_ = cb; 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.signer_ = new MultipleGnubbySigner( 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch true /* forEnroll */, 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.signerCompleted_.bind(this), 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.signerFoundGnubby_.bind(this), 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch timeoutMillis, 556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.request_.logMsgUrl); 566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return this.signer_.doSign(this.request_.signData); 575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** Closes this helper. */ 606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.close = function() { 615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.closed_ = true; 625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var i = 0; i < this.waitingForTouchGnubbies_.length; i++) { 635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.waitingForTouchGnubbies_[i].closeWhenIdle(); 645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.waitingForTouchGnubbies_ = []; 665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.signer_) { 675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signer_.close(); 685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.signer_ = null; 695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when a MultipleGnubbySigner completes its sign request. 74116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {boolean} anyPending Whether any gnubbies are pending. 755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.signerCompleted_ = function(anyPending) { 78116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!this.anyGnubbiesFound_ || this.anyTimeout_ || anyPending || 79116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.timer_.expired()) { 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.notifyError_(DeviceStatusCodes.TIMEOUT_STATUS); 815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Do nothing: signerFoundGnubby will have been called with each succeeding 835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // gnubby. 845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called when a MultipleGnubbySigner finds a gnubby that can enroll. 89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {MultipleSignerResult} signResult Signature results 90116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {boolean} moreExpected Whether the signer expects to report 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * results from more gnubbies. 925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.signerFoundGnubby_ = 95116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch function(signResult, moreExpected) { 96116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!signResult.code) { 97116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // If the signer reports a gnubby can sign, report this immediately to the 986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // caller, as the gnubby is already enrolled. Map ok to WRONG_DATA, so the 996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // caller knows what to do. 1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.notifyError_(DeviceStatusCodes.WRONG_DATA_STATUS); 1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } else if (signResult.code == DeviceStatusCodes.WRONG_DATA_STATUS || 1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci signResult.code == DeviceStatusCodes.WRONG_LENGTH_STATUS) { 103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var gnubby = signResult['gnubby']; 1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // A valid helper request contains at least one enroll challenge, so use 1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // the app id hash from the first challenge. 1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var appIdHash = this.request_.enrollChallenges[0].appIdHash; 1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DEVICE_FACTORY_REGISTRY.getGnubbyFactory().notEnrolledPrerequisiteCheck( 1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) gnubby, appIdHash, this.gnubbyPrerequisitesChecked_.bind(this)); 1095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * Called with the result of a gnubby prerequisite check. 1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {number} rc The result of the prerequisite check. 1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby=} opt_gnubby The gnubby whose prerequisites were checked. 1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @private 1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) */ 1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.gnubbyPrerequisitesChecked_ = 1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) function(rc, opt_gnubby) { 1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if (rc || this.timer_.expired()) { 1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // Do nothing: 1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the timer is expired, the signerCompleted_ callback will indicate 1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // timeout to the caller. 1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If there's an error, this gnubby is ineligible, but there's nothing we 1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // can do about that here. 1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return; 1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } 1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) // If the callback succeeded, the gnubby is not null. 1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) var gnubby = /** @type {Gnubby} */ (opt_gnubby); 1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.anyGnubbiesFound_ = true; 1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.waitingForTouchGnubbies_.push(gnubby); 1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.matchEnrollVersionToGnubby_(gnubby); 1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}; 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)/** 1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Attempts to match the gnubby's U2F version with an appropriate enroll 1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * challenge. 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.matchEnrollVersionToGnubby_ = function(gnubby) { 1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!gnubby) { 1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.warn(UTIL_fmt('no gnubby, WTF?')); 1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return; 1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu gnubby.version(this.gnubbyVersioned_.bind(this, gnubby)); 1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called with the result of a version command. 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 1525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {number} rc result of version command. 1535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @param {ArrayBuffer=} data version. 1545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.gnubbyVersioned_ = function(gnubby, rc, data) { 1575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (rc) { 1585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.removeWrongVersionGnubby_(gnubby); 1595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 1605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var version = UTIL_BytesToString(new Uint8Array(data || null)); 1625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.tryEnroll_(gnubby, version); 1635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Drops the gnubby from the list of eligible gnubbies. 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 1685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.removeWaitingGnubby_ = function(gnubby) { 1715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu gnubby.closeWhenIdle(); 1725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var index = this.waitingForTouchGnubbies_.indexOf(gnubby); 1735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (index >= 0) { 1745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.waitingForTouchGnubbies_.splice(index, 1); 1755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Drops the gnubby from the list of eligible gnubbies, as it has the wrong 1805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * version. 1816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 1825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 1835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.removeWrongVersionGnubby_ = function(gnubby) { 1855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.removeWaitingGnubby_(gnubby); 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!this.waitingForTouchGnubbies_.length) { 187116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Whoops, this was the last gnubby. 188116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.anyGnubbiesFound_ = false; 189116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (this.timer_.expired()) { 190116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.notifyError_(DeviceStatusCodes.TIMEOUT_STATUS); 1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (this.signer_) { 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.signer_.reScanDevices(); 193116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 1945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 1955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 1965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 1975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Attempts enrolling a particular gnubby with a challenge of the appropriate 1995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * version. 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 201010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} version Protocol version 2025c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2035c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.tryEnroll_ = function(gnubby, version) { 2055c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var challenge = this.getChallengeOfVersion_(version); 2065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!challenge) { 2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.removeWrongVersionGnubby_(gnubby); 2085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci var challengeValue = B64_decode(challenge['challengeHash']); 2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci var appIdHash = challenge['appIdHash']; 2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci var individualAttest = 2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci DEVICE_FACTORY_REGISTRY.getIndividualAttestation(). 2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci requestIndividualAttestation(appIdHash); 2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci gnubby.enroll(challengeValue, B64_decode(appIdHash), 2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci this.enrollCallback_.bind(this, gnubby, version), individualAttest); 2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Finds the (first) challenge of the given version in this helper's challenges. 221010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} version Protocol version 2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @return {Object} challenge, if found, or null if not. 2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.getChallengeOfVersion_ = function(version) { 2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu for (var i = 0; i < this.enrollChallenges.length; i++) { 2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.enrollChallenges[i]['version'] == version) { 2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return this.enrollChallenges[i]; 2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return null; 2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * Called with the result of an enroll request to a gnubby. 2366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) * @param {Gnubby} gnubby Gnubby instance 237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} version Protocol version 238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {number} code Status code 239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {ArrayBuffer=} infoArray Returned data 2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 2426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.enrollCallback_ = 2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu function(gnubby, version, code, infoArray) { 2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.notified_) { 2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Enroll completed after previous success or failure. Disregard. 2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu switch (code) { 2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) case -GnubbyDevice.GONE: 2505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Close this gnubby. 2515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.removeWaitingGnubby_(gnubby); 2525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (!this.waitingForTouchGnubbies_.length) { 253116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Last enroll attempt is complete and last gnubby is gone. 254116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.anyGnubbiesFound_ = false; 255116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (this.timer_.expired()) { 256116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.notifyError_(DeviceStatusCodes.TIMEOUT_STATUS); 2576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) } else if (this.signer_) { 2586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) this.signer_.reScanDevices(); 259116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch } 2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.WAIT_TOUCH_STATUS: 2645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.BUSY_STATUS: 2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.TIMEOUT_STATUS: 2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.timer_.expired()) { 267116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Record that at least one gnubby timed out, to return a timeout status 268116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // from the complete callback if no other eligible gnubbies are found. 269116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch /** @private {boolean} */ 270116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.anyTimeout_ = true; 2715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Close this gnubby. 2725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.removeWaitingGnubby_(gnubby); 273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (!this.waitingForTouchGnubbies_.length) { 2745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu // Last enroll attempt is complete: return this error. 2755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('timeout (' + code.toString(16) + 2765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu ') enrolling')); 277116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.notifyError_(DeviceStatusCodes.TIMEOUT_STATUS); 2785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } else { 2806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DEVICE_FACTORY_REGISTRY.getCountdownFactory().createTimer( 2816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) UsbEnrollHandler.ENUMERATE_DELAY_INTERVAL_MILLIS, 282116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.tryEnroll_.bind(this, gnubby, version)); 2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 2855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu case DeviceStatusCodes.OK_STATUS: 2875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu var info = B64_encode(new Uint8Array(infoArray || [])); 2885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notifySuccess_(version, info); 2895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 2905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu default: 2925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu console.log(UTIL_fmt('Failed to enroll gnubby: ' + code)); 293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.notifyError_(code); 2945c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu break; 2955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu } 2965c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 2975c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 2985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * How long to delay between repeated enroll attempts, in milliseconds. 300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @const 301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch */ 3026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.ENUMERATE_DELAY_INTERVAL_MILLIS = 200; 303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch/** 305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * Notifies the callback with an error code. 306116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch * @param {number} code The error code to report. 3075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 3085c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.notifyError_ = function(code) { 3105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.notified_ || this.closed_) 3115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 3125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notified_ = true; 3135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.close(); 314116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var reply = { 315116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'type': 'enroll_helper_reply', 316116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'code': code 317116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch }; 318116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.cb_(reply); 3195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 3205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu 3215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/** 322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} version Protocol version 323010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) * @param {string} info B64 encoded success data 3245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu * @private 3255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu */ 3266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)UsbEnrollHandler.prototype.notifySuccess_ = function(version, info) { 3275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu if (this.notified_ || this.closed_) 3285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu return; 3295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.notified_ = true; 3305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu this.close(); 331116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch var reply = { 332116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'type': 'enroll_helper_reply', 333116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'code': DeviceStatusCodes.OK_STATUS, 334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'version': version, 335116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'enrollData': info 336116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch }; 337116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch this.cb_(reply); 3385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}; 339