Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2376)

Unified Diff: chrome/browser/resources/cryptotoken/multiplesigner.js

Issue 249913002: FIDO U2F component extension (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merge with HEAD Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/cryptotoken/multiplesigner.js
diff --git a/chrome/browser/resources/cryptotoken/multiplesigner.js b/chrome/browser/resources/cryptotoken/multiplesigner.js
new file mode 100644
index 0000000000000000000000000000000000000000..86d5e1a8d95e623fad4a23667fcc631ec2551b42
--- /dev/null
+++ b/chrome/browser/resources/cryptotoken/multiplesigner.js
@@ -0,0 +1,276 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/**
+ * @fileoverview A multiple gnubby signer wraps the process of opening a number
+ * of gnubbies, signing each challenge in an array of challenges until a
+ * success condition is satisfied, and yielding each succeeding gnubby.
+ *
+ * @author juanlang@google.com (Juan Lang)
+ */
+'use strict';
+
+/**
+ * Creates a new sign handler with an array of gnubby indexes.
+ * @param {!GnubbyFactory} factory Used to create and open the gnubbies.
+ * @param {Array.<llGnubbyDeviceId>} gnubbyIndexes Which gnubbies to open.
+ * @param {boolean} forEnroll Whether this signer is signing for an attempted
+ * enroll operation.
+ * @param {function(boolean, (number|undefined))} completedCb Called when this
+ * signer completes sign attempts, i.e. no further results should be
+ * expected.
+ * @param {function(number, MultipleSignerResult)} gnubbyFoundCb Called with
+ * each gnubby/challenge that yields a successful result.
+ * @param {Countdown=} opt_timer An advisory timer, beyond whose expiration the
+ * signer will not attempt any new operations, assuming the caller is no
+ * longer interested in the outcome.
+ * @param {string=} opt_logMsgUrl A URL to post log messages to.
+ * @constructor
+ */
+function MultipleGnubbySigner(factory, gnubbyIndexes, forEnroll, completedCb,
+ gnubbyFoundCb, opt_timer, opt_logMsgUrl) {
+ /** @private {!GnubbyFactory} */
+ this.factory_ = factory;
+ /** @private {Array.<llGnubbyDeviceId>} */
+ this.gnubbyIndexes_ = gnubbyIndexes;
+ /** @private {boolean} */
+ this.forEnroll_ = forEnroll;
+ /** @private {function(boolean, (number|undefined))} */
+ this.completedCb_ = completedCb;
+ /** @private {function(number, MultipleSignerResult)} */
+ this.gnubbyFoundCb_ = gnubbyFoundCb;
+ /** @private {Countdown|undefined} */
+ this.timer_ = opt_timer;
+ /** @private {string|undefined} */
+ this.logMsgUrl_ = opt_logMsgUrl;
+
+ /** @private {Array.<SignHelperChallenge>} */
+ this.challenges_ = [];
+ /** @private {boolean} */
+ this.challengesFinal_ = false;
+
+ // Create a signer for each gnubby.
+ /** @private {boolean} */
+ this.anySucceeded_ = false;
+ /** @private {number} */
+ this.numComplete_ = 0;
+ /** @private {Array.<SingleGnubbySigner>} */
+ this.signers_ = [];
+ /** @private {Array.<boolean>} */
+ this.stillGoing_ = [];
+ /** @private {Array.<number>} */
+ this.errorStatus_ = [];
+ for (var i = 0; i < gnubbyIndexes.length; i++) {
+ this.addGnubby(gnubbyIndexes[i]);
+ }
+}
+
+/**
+ * Attempts to open this signer's gnubbies, if they're not already open.
+ * (This is implicitly done by addChallenges.)
+ */
+MultipleGnubbySigner.prototype.open = function() {
+ for (var i = 0; i < this.signers_.length; i++) {
+ this.signers_[i].open();
+ }
+};
+
+/**
+ * Closes this signer's gnubbies, if any are open.
+ */
+MultipleGnubbySigner.prototype.close = function() {
+ for (var i = 0; i < this.signers_.length; i++) {
+ this.signers_[i].close();
+ }
+};
+
+/**
+ * Adds challenges to the set of challenges being tried by this signer.
+ * The challenges are an array of challenge objects, where each challenge
+ * object's values are base64-encoded.
+ * If the signer is currently idle, begins signing the new challenges.
+ *
+ * @param {Array} challenges
+ * @param {boolean} finalChallenges
+ * @return {boolean} whether the challenges were successfully added.
+ * @public
+ */
+MultipleGnubbySigner.prototype.addEncodedChallenges =
+ function(challenges, finalChallenges) {
+ var decodedChallenges = [];
+ if (challenges) {
+ for (var i = 0; i < challenges.length; i++) {
+ var decodedChallenge = {};
+ var challenge = challenges[i];
+ decodedChallenge['challengeHash'] =
+ B64_decode(challenge['challengeHash']);
+ decodedChallenge['appIdHash'] = B64_decode(challenge['appIdHash']);
+ decodedChallenge['keyHandle'] = B64_decode(challenge['keyHandle']);
+ if (challenge['version']) {
+ decodedChallenge['version'] = challenge['version'];
+ }
+ decodedChallenges.push(decodedChallenge);
+ }
+ }
+ return this.addChallenges(decodedChallenges, finalChallenges);
+};
+
+/**
+ * Adds challenges to the set of challenges being tried by this signer.
+ * If the signer is currently idle, begins signing the new challenges.
+ *
+ * @param {Array.<SignHelperChallenge>} challenges
+ * @param {boolean} finalChallenges
+ * @return {boolean} whether the challenges were successfully added.
+ * @public
+ */
+MultipleGnubbySigner.prototype.addChallenges =
+ function(challenges, finalChallenges) {
+ if (this.challengesFinal_) {
+ // Can't add new challenges once they're finalized.
+ return false;
+ }
+
+ if (challenges) {
+ for (var i = 0; i < challenges.length; i++) {
+ this.challenges_.push(challenges[i]);
+ }
+ }
+ this.challengesFinal_ = finalChallenges;
+
+ for (var i = 0; i < this.signers_.length; i++) {
+ this.stillGoing_[i] =
+ this.signers_[i].addChallenges(challenges, finalChallenges);
+ this.errorStatus_[i] = 0;
+ }
+ return true;
+};
+
+/**
+ * Adds a new gnubby to this signer's list of gnubbies. (Only possible while
+ * this signer is still signing: without this restriction, the morePossible
+ * indication in the callbacks could become violated.) If this signer has
+ * challenges to sign, begins signing on the new gnubby with them.
+ * @param {llGnubbyDeviceId} gnubbyIndex The index of the gnubby to add.
+ * @return {boolean} Whether the gnubby was added successfully.
+ * @public
+ */
+MultipleGnubbySigner.prototype.addGnubby = function(gnubbyIndex) {
+ if (this.numComplete_ && this.numComplete_ == this.signers_.length)
+ return false;
+
+ var index = this.signers_.length;
+ this.signers_.push(
+ new SingleGnubbySigner(
+ this.factory_,
+ gnubbyIndex,
+ this.forEnroll_,
+ this.signFailedCallback_.bind(this, index),
+ this.signSucceededCallback_.bind(this, index),
+ this.timer_ ? this.timer_.clone() : null,
+ this.logMsgUrl_));
+ this.stillGoing_.push(false);
+
+ if (this.challenges_.length) {
+ this.stillGoing_[index] =
+ this.signers_[index].addChallenges(this.challenges_,
+ this.challengesFinal_);
+ }
+ return true;
+};
+
+/**
+ * Called by a SingleGnubbySigner upon failure, i.e. unsuccessful completion of
+ * all its sign operations.
+ * @param {number} index the index of the gnubby whose result this is
+ * @param {number} code the result code of the sign operation
+ * @private
+ */
+MultipleGnubbySigner.prototype.signFailedCallback_ = function(index, code) {
+ console.log(
+ UTIL_fmt('failure. gnubby ' + index + ' got code ' + code.toString(16)));
+ if (!this.stillGoing_[index]) {
+ console.log(UTIL_fmt('gnubby ' + index + ' no longer running!'));
+ // Shouldn't ever happen? Disregard.
+ return;
+ }
+ this.stillGoing_[index] = false;
+ this.errorStatus_[index] = code;
+ this.numComplete_++;
+ var morePossible = this.numComplete_ < this.signers_.length;
+ if (!morePossible)
+ this.notifyComplete_();
+};
+
+/**
+ * Called by a SingleGnubbySigner upon success.
+ * @param {number} index the index of the gnubby whose result this is
+ * @param {usbGnubby} gnubby the underlying gnubby that succeded.
+ * @param {number} code the result code of the sign operation
+ * @param {SingleSignerResult=} signResult
+ * @private
+ */
+MultipleGnubbySigner.prototype.signSucceededCallback_ =
+ function(index, gnubby, code, signResult) {
+ console.log(UTIL_fmt('success! gnubby ' + index + ' got code ' +
+ code.toString(16)));
+ if (!this.stillGoing_[index]) {
+ console.log(UTIL_fmt('gnubby ' + index + ' no longer running!'));
+ // Shouldn't ever happen? Disregard.
+ return;
+ }
+ this.anySucceeded_ = true;
+ this.stillGoing_[index] = false;
+ this.notifySuccess_(code, gnubby, index, signResult);
+ this.numComplete_++;
+ var morePossible = this.numComplete_ < this.signers_.length;
+ if (!morePossible)
+ this.notifyComplete_();
+};
+
+/**
+ * @private
+ */
+MultipleGnubbySigner.prototype.notifyComplete_ = function() {
+ // See if any of the signers failed with a strange error. If so, report a
+ // single error to the caller, partly as a diagnostic aid and partly to
+ // distinguish real failures from wrong data.
+ var funnyBusiness;
+ for (var i = 0; i < this.errorStatus_.length; i++) {
+ if (this.errorStatus_[i] &&
+ this.errorStatus_[i] != DeviceStatusCodes.WRONG_DATA_STATUS &&
+ this.errorStatus_[i] != DeviceStatusCodes.WAIT_TOUCH_STATUS) {
+ funnyBusiness = this.errorStatus_[i];
+ break;
+ }
+ }
+ if (funnyBusiness) {
+ console.warn(UTIL_fmt('all done (success: ' + this.anySucceeded_ + ', ' +
+ 'funny error = ' + funnyBusiness + ')'));
+ } else {
+ console.log(UTIL_fmt('all done (success: ' + this.anySucceeded_ + ')'));
+ }
+ this.completedCb_(this.anySucceeded_, funnyBusiness);
+};
+
+/**
+ * @param {number} code
+ * @param {usbGnubby} gnubby
+ * @param {number} gnubbyIndex
+ * @param {SingleSignerResult=} singleSignerResult
+ * @private
+ */
+MultipleGnubbySigner.prototype.notifySuccess_ =
+ function(code, gnubby, gnubbyIndex, singleSignerResult) {
+ console.log(UTIL_fmt('success (' + code.toString(16) + ')'));
+ var signResult = {
+ 'gnubby': gnubby,
+ 'gnubbyIndex': gnubbyIndex
+ };
+ if (singleSignerResult && singleSignerResult['challenge'])
+ signResult['challenge'] = singleSignerResult['challenge'];
+ if (singleSignerResult && singleSignerResult['info'])
+ signResult['info'] = singleSignerResult['info'];
+ this.gnubbyFoundCb_(code, signResult);
+};
« no previous file with comments | « chrome/browser/resources/cryptotoken/manifest.json ('k') | chrome/browser/resources/cryptotoken/requestqueue.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698