| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @fileoverview A single gnubby signer wraps the process of opening a gnubby, | 6 * @fileoverview A single gnubby signer wraps the process of opening a gnubby, |
| 7 * signing each challenge in an array of challenges until a success condition | 7 * signing each challenge in an array of challenges until a success condition |
| 8 * is satisfied, and finally yielding the gnubby upon success. | 8 * is satisfied, and finally yielding the gnubby upon success. |
| 9 * | 9 * |
| 10 */ | 10 */ |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 /** @private {string|undefined} */ | 65 /** @private {string|undefined} */ |
| 66 this.logMsgUrl_ = opt_logMsgUrl; | 66 this.logMsgUrl_ = opt_logMsgUrl; |
| 67 | 67 |
| 68 /** @private {!Array.<!SignHelperChallenge>} */ | 68 /** @private {!Array.<!SignHelperChallenge>} */ |
| 69 this.challenges_ = []; | 69 this.challenges_ = []; |
| 70 /** @private {number} */ | 70 /** @private {number} */ |
| 71 this.challengeIndex_ = 0; | 71 this.challengeIndex_ = 0; |
| 72 /** @private {boolean} */ | 72 /** @private {boolean} */ |
| 73 this.challengesSet_ = false; | 73 this.challengesSet_ = false; |
| 74 | 74 |
| 75 /** @private {!Array.<string>} */ | 75 /** @private {!Object.<string, number>} */ |
| 76 this.notForMe_ = []; | 76 this.cachedError_ = []; |
| 77 } | 77 } |
| 78 | 78 |
| 79 /** @enum {number} */ | 79 /** @enum {number} */ |
| 80 SingleGnubbySigner.State = { | 80 SingleGnubbySigner.State = { |
| 81 /** Initial state. */ | 81 /** Initial state. */ |
| 82 INIT: 0, | 82 INIT: 0, |
| 83 /** The signer is attempting to open a gnubby. */ | 83 /** The signer is attempting to open a gnubby. */ |
| 84 OPENING: 1, | 84 OPENING: 1, |
| 85 /** The signer's gnubby opened, but is busy. */ | 85 /** The signer's gnubby opened, but is busy. */ |
| 86 BUSY: 2, | 86 BUSY: 2, |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 } | 235 } |
| 236 }, SingleGnubbySigner.OPEN_DELAY_MILLIS); | 236 }, SingleGnubbySigner.OPEN_DELAY_MILLIS); |
| 237 } else { | 237 } else { |
| 238 this.goToError_(DeviceStatusCodes.BUSY_STATUS); | 238 this.goToError_(DeviceStatusCodes.BUSY_STATUS); |
| 239 } | 239 } |
| 240 break; | 240 break; |
| 241 default: | 241 default: |
| 242 // TODO: This won't be confused with success, but should it be | 242 // TODO: This won't be confused with success, but should it be |
| 243 // part of the same namespace as the other error codes, which are | 243 // part of the same namespace as the other error codes, which are |
| 244 // always in DeviceStatusCodes.*? | 244 // always in DeviceStatusCodes.*? |
| 245 this.goToError_(rc); | 245 this.goToError_(rc, true); |
| 246 } | 246 } |
| 247 }; | 247 }; |
| 248 | 248 |
| 249 /** | 249 /** |
| 250 * Called with the result of a version command. | 250 * Called with the result of a version command. |
| 251 * @param {number} rc Result of version command. | 251 * @param {number} rc Result of version command. |
| 252 * @param {ArrayBuffer=} opt_data Version. | 252 * @param {ArrayBuffer=} opt_data Version. |
| 253 * @private | 253 * @private |
| 254 */ | 254 */ |
| 255 SingleGnubbySigner.prototype.versionCallback_ = function(rc, opt_data) { | 255 SingleGnubbySigner.prototype.versionCallback_ = function(rc, opt_data) { |
| 256 if (rc) { | 256 if (rc) { |
| 257 this.goToError_(rc); | 257 this.goToError_(rc, true); |
| 258 return; | 258 return; |
| 259 } | 259 } |
| 260 this.state_ = SingleGnubbySigner.State.IDLE; | 260 this.state_ = SingleGnubbySigner.State.IDLE; |
| 261 this.version_ = UTIL_BytesToString(new Uint8Array(opt_data || [])); | 261 this.version_ = UTIL_BytesToString(new Uint8Array(opt_data || [])); |
| 262 this.doSign_(this.challengeIndex_); | 262 this.doSign_(this.challengeIndex_); |
| 263 }; | 263 }; |
| 264 | 264 |
| 265 /** | 265 /** |
| 266 * @param {number} challengeIndex Index of challenge to sign | 266 * @param {number} challengeIndex Index of challenge to sign |
| 267 * @private | 267 * @private |
| (...skipping 20 matching lines...) Expand all Loading... |
| 288 | 288 |
| 289 if (challengeIndex >= this.challenges_.length) { | 289 if (challengeIndex >= this.challenges_.length) { |
| 290 this.signCallback_(challengeIndex, DeviceStatusCodes.WRONG_DATA_STATUS); | 290 this.signCallback_(challengeIndex, DeviceStatusCodes.WRONG_DATA_STATUS); |
| 291 return; | 291 return; |
| 292 } | 292 } |
| 293 | 293 |
| 294 var challenge = this.challenges_[challengeIndex]; | 294 var challenge = this.challenges_[challengeIndex]; |
| 295 var challengeHash = challenge.challengeHash; | 295 var challengeHash = challenge.challengeHash; |
| 296 var appIdHash = challenge.appIdHash; | 296 var appIdHash = challenge.appIdHash; |
| 297 var keyHandle = challenge.keyHandle; | 297 var keyHandle = challenge.keyHandle; |
| 298 if (this.notForMe_.indexOf(keyHandle) != -1) { | 298 if (this.cachedError_.hasOwnProperty(keyHandle)) { |
| 299 // Cache hit: return wrong data again. | 299 // Cache hit: return wrong data again. |
| 300 this.signCallback_(challengeIndex, DeviceStatusCodes.WRONG_DATA_STATUS); | 300 this.signCallback_(challengeIndex, this.cachedError_[keyHandle]); |
| 301 } else if (challenge.version && challenge.version != this.version_) { | 301 } else if (challenge.version && challenge.version != this.version_) { |
| 302 // Sign challenge for a different version of gnubby: return wrong data. | 302 // Sign challenge for a different version of gnubby: return wrong data. |
| 303 this.signCallback_(challengeIndex, DeviceStatusCodes.WRONG_DATA_STATUS); | 303 this.signCallback_(challengeIndex, DeviceStatusCodes.WRONG_DATA_STATUS); |
| 304 } else { | 304 } else { |
| 305 var nowink = false; | 305 var nowink = false; |
| 306 this.gnubby_.sign(challengeHash, appIdHash, keyHandle, | 306 this.gnubby_.sign(challengeHash, appIdHash, keyHandle, |
| 307 this.signCallback_.bind(this, challengeIndex), | 307 this.signCallback_.bind(this, challengeIndex), |
| 308 nowink); | 308 nowink); |
| 309 } | 309 } |
| 310 }; | 310 }; |
| 311 | 311 |
| 312 /** | 312 /** |
| 313 * Called with the result of a single sign operation. | 313 * Called with the result of a single sign operation. |
| 314 * @param {number} challengeIndex the index of the challenge just attempted | 314 * @param {number} challengeIndex the index of the challenge just attempted |
| 315 * @param {number} code the result of the sign operation | 315 * @param {number} code the result of the sign operation |
| 316 * @param {ArrayBuffer=} opt_info Optional result data | 316 * @param {ArrayBuffer=} opt_info Optional result data |
| 317 * @private | 317 * @private |
| 318 */ | 318 */ |
| 319 SingleGnubbySigner.prototype.signCallback_ = | 319 SingleGnubbySigner.prototype.signCallback_ = |
| 320 function(challengeIndex, code, opt_info) { | 320 function(challengeIndex, code, opt_info) { |
| 321 console.log(UTIL_fmt('gnubby ' + JSON.stringify(this.gnubbyId_) + | 321 console.log(UTIL_fmt('gnubby ' + JSON.stringify(this.gnubbyId_) + |
| 322 ', challenge ' + challengeIndex + ' yielded ' + code.toString(16))); | 322 ', challenge ' + challengeIndex + ' yielded ' + code.toString(16))); |
| 323 if (this.state_ != SingleGnubbySigner.State.SIGNING) { | 323 if (this.state_ != SingleGnubbySigner.State.SIGNING) { |
| 324 console.log(UTIL_fmt('already done!')); | 324 console.log(UTIL_fmt('already done!')); |
| 325 // We're done, the caller's no longer interested. | 325 // We're done, the caller's no longer interested. |
| 326 return; | 326 return; |
| 327 } | 327 } |
| 328 | 328 |
| 329 // Cache wrong data result, re-asking the gnubby to sign it won't produce | 329 // Cache wrong data or wrong length results, re-asking the gnubby to sign it |
| 330 // different results. | 330 // won't produce different results. |
| 331 if (code == DeviceStatusCodes.WRONG_DATA_STATUS) { | 331 if (code == DeviceStatusCodes.WRONG_DATA_STATUS || |
| 332 code == DeviceStatusCodes.WRONG_LENGTH_STATUS) { |
| 332 if (challengeIndex < this.challenges_.length) { | 333 if (challengeIndex < this.challenges_.length) { |
| 333 var challenge = this.challenges_[challengeIndex]; | 334 var challenge = this.challenges_[challengeIndex]; |
| 334 if (this.notForMe_.indexOf(challenge.keyHandle) == -1) { | 335 if (!this.cachedError_.hasOwnProperty(challenge.keyHandle)) { |
| 335 this.notForMe_.push(challenge.keyHandle); | 336 this.cachedError_[challenge.keyHandle] = code; |
| 336 } | 337 } |
| 337 } | 338 } |
| 338 } | 339 } |
| 339 | 340 |
| 340 var self = this; | 341 var self = this; |
| 341 switch (code) { | 342 switch (code) { |
| 342 case DeviceStatusCodes.GONE_STATUS: | 343 case DeviceStatusCodes.GONE_STATUS: |
| 343 this.goToError_(code); | 344 this.goToError_(code); |
| 344 break; | 345 break; |
| 345 | 346 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 357 } | 358 } |
| 358 break; | 359 break; |
| 359 | 360 |
| 360 case DeviceStatusCodes.WAIT_TOUCH_STATUS: | 361 case DeviceStatusCodes.WAIT_TOUCH_STATUS: |
| 361 window.setTimeout(function() { | 362 window.setTimeout(function() { |
| 362 self.doSign_(self.challengeIndex_); | 363 self.doSign_(self.challengeIndex_); |
| 363 }, SingleGnubbySigner.SIGN_DELAY_MILLIS); | 364 }, SingleGnubbySigner.SIGN_DELAY_MILLIS); |
| 364 break; | 365 break; |
| 365 | 366 |
| 366 case DeviceStatusCodes.WRONG_DATA_STATUS: | 367 case DeviceStatusCodes.WRONG_DATA_STATUS: |
| 368 case DeviceStatusCodes.WRONG_LENGTH_STATUS: |
| 367 if (this.challengeIndex_ < this.challenges_.length - 1) { | 369 if (this.challengeIndex_ < this.challenges_.length - 1) { |
| 368 this.doSign_(++this.challengeIndex_); | 370 this.doSign_(++this.challengeIndex_); |
| 369 } else if (this.forEnroll_) { | 371 } else if (this.forEnroll_) { |
| 370 this.goToSuccess_(code); | 372 this.goToSuccess_(code); |
| 371 } else { | 373 } else { |
| 372 this.goToError_(code); | 374 this.goToError_(code); |
| 373 } | 375 } |
| 374 break; | 376 break; |
| 375 | 377 |
| 376 default: | 378 default: |
| 377 if (this.forEnroll_) { | 379 if (this.forEnroll_) { |
| 378 this.goToError_(code); | 380 this.goToError_(code, true); |
| 379 } else if (this.challengeIndex_ < this.challenges_.length - 1) { | 381 } else if (this.challengeIndex_ < this.challenges_.length - 1) { |
| 380 this.doSign_(++this.challengeIndex_); | 382 this.doSign_(++this.challengeIndex_); |
| 381 } else { | 383 } else { |
| 382 this.goToError_(code); | 384 this.goToError_(code, true); |
| 383 } | 385 } |
| 384 } | 386 } |
| 385 }; | 387 }; |
| 386 | 388 |
| 387 /** | 389 /** |
| 388 * Switches to the error state, and notifies caller. | 390 * Switches to the error state, and notifies caller. |
| 389 * @param {number} code Error code | 391 * @param {number} code Error code |
| 392 * @param {boolean=} opt_warn Whether to warn in the console about the error. |
| 390 * @private | 393 * @private |
| 391 */ | 394 */ |
| 392 SingleGnubbySigner.prototype.goToError_ = function(code) { | 395 SingleGnubbySigner.prototype.goToError_ = function(code, opt_warn) { |
| 393 this.state_ = SingleGnubbySigner.State.COMPLETE; | 396 this.state_ = SingleGnubbySigner.State.COMPLETE; |
| 394 console.log(UTIL_fmt('failed (' + code.toString(16) + ')')); | 397 var logFn = opt_warn ? console.warn.bind(console) : console.log.bind(console); |
| 398 logFn(UTIL_fmt('failed (' + code.toString(16) + ')')); |
| 395 // Since this gnubby can no longer produce a useful result, go ahead and | 399 // Since this gnubby can no longer produce a useful result, go ahead and |
| 396 // close it. | 400 // close it. |
| 397 this.close(); | 401 this.close(); |
| 398 var result = { code: code }; | 402 var result = { code: code }; |
| 399 this.completeCb_(result); | 403 this.completeCb_(result); |
| 400 }; | 404 }; |
| 401 | 405 |
| 402 /** | 406 /** |
| 403 * Switches to the success state, and notifies caller. | 407 * Switches to the success state, and notifies caller. |
| 404 * @param {number} code Status code | 408 * @param {number} code Status code |
| (...skipping 11 matching lines...) Expand all Loading... |
| 416 result['challenge'] = opt_challenge; | 420 result['challenge'] = opt_challenge; |
| 417 } | 421 } |
| 418 if (opt_info) { | 422 if (opt_info) { |
| 419 result['info'] = opt_info; | 423 result['info'] = opt_info; |
| 420 } | 424 } |
| 421 } | 425 } |
| 422 this.completeCb_(result); | 426 this.completeCb_(result); |
| 423 // this.gnubby_ is now owned by completeCb_. | 427 // this.gnubby_ is now owned by completeCb_. |
| 424 this.gnubby_ = null; | 428 this.gnubby_ = null; |
| 425 }; | 429 }; |
| OLD | NEW |