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
3 // found in the LICENSE file.
6 * @fileoverview Implements a sign handler using USB gnubbies.
10 var CORRUPT_sign = false;
13 * @param {!SignHelperRequest} request The sign request.
15 * @implements {RequestHandler}
17 function UsbSignHandler(request) {
18 /** @private {!SignHelperRequest} */
19 this.request_ = request;
21 /** @private {boolean} */
22 this.notified_ = false;
23 /** @private {boolean} */
24 this.anyGnubbiesFound_ = false;
28 * Default timeout value in case the caller never provides a valid timeout.
31 UsbSignHandler.DEFAULT_TIMEOUT_MILLIS = 30 * 1000;
34 * Attempts to run this handler's request.
35 * @param {RequestHandlerCallback} cb Called with the result of the request and
36 * an optional source for the sign result.
37 * @return {boolean} whether this set of challenges was accepted.
39 UsbSignHandler.prototype.run = function(cb) {
41 // Can only handle one request.
44 /** @private {RequestHandlerCallback} */
46 if (!this.request_.signData || !this.request_.signData.length) {
47 // Fail a sign request with an empty set of challenges, and pretend to have
48 // alerted the caller in case the enumerate is still pending.
49 this.notified_ = true;
53 this.request_.timeoutSeconds ?
54 this.request_.timeoutSeconds * 1000 :
55 UsbSignHandler.DEFAULT_TIMEOUT_MILLIS;
56 /** @private {MultipleGnubbySigner} */
57 this.signer_ = new MultipleGnubbySigner(
58 false /* forEnroll */,
59 this.signerCompleted_.bind(this),
60 this.signerFoundGnubby_.bind(this),
62 this.request_.logMsgUrl);
63 return this.signer_.doSign(this.request_.signData);
68 * Called when a MultipleGnubbySigner completes.
69 * @param {boolean} anyPending Whether any gnubbies are pending.
72 UsbSignHandler.prototype.signerCompleted_ = function(anyPending) {
73 if (!this.anyGnubbiesFound_ || anyPending) {
74 this.notifyError_(DeviceStatusCodes.TIMEOUT_STATUS);
75 } else if (this.signerError_ !== undefined) {
76 this.notifyError_(this.signerError_);
78 // Do nothing: signerFoundGnubby_ will have returned results from other
84 * Called when a MultipleGnubbySigner finds a gnubby that has completed signing
86 * @param {MultipleSignerResult} signResult Signer result object
87 * @param {boolean} moreExpected Whether the signer expects to produce more
91 UsbSignHandler.prototype.signerFoundGnubby_ =
92 function(signResult, moreExpected) {
93 this.anyGnubbiesFound_ = true;
94 if (!signResult.code) {
95 var gnubby = signResult['gnubby'];
96 var challenge = signResult['challenge'];
97 var info = new Uint8Array(signResult['info']);
98 this.notifySuccess_(gnubby, challenge, info);
99 } else if (!moreExpected) {
100 // If the signer doesn't expect more results, return the error directly to
102 this.notifyError_(signResult.code);
104 // Record the last error, to report from the complete callback if no other
105 // eligible gnubbies are found.
106 /** @private {number} */
107 this.signerError_ = signResult.code;
112 * Reports the result of a successful sign operation.
113 * @param {Gnubby} gnubby Gnubby instance
114 * @param {SignHelperChallenge} challenge Challenge signed
115 * @param {Uint8Array} info Result data
118 UsbSignHandler.prototype.notifySuccess_ = function(gnubby, challenge, info) {
121 this.notified_ = true;
123 gnubby.closeWhenIdle();
127 CORRUPT_sign = false;
128 info[info.length - 1] = info[info.length - 1] ^ 0xff;
131 'appIdHash': B64_encode(challenge['appIdHash']),
132 'challengeHash': B64_encode(challenge['challengeHash']),
133 'keyHandle': B64_encode(challenge['keyHandle']),
134 'signatureData': B64_encode(info)
137 'type': 'sign_helper_reply',
138 'code': DeviceStatusCodes.OK_STATUS,
139 'responseData': responseData
141 this.cb_(reply, 'USB');
145 * Reports error to the caller.
146 * @param {number} code error to report
149 UsbSignHandler.prototype.notifyError_ = function(code) {
152 this.notified_ = true;
155 'type': 'sign_helper_reply',
162 * Closes the MultipleGnubbySigner, if any.
164 UsbSignHandler.prototype.close = function() {
166 this.signer_.close();