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

Side by Side Diff: chrome/browser/resources/cryptotoken/enroller.js

Issue 596083002: Update cryptotoken to 0.8.63 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Remove a deprecated line Created 6 years, 2 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 unified diff | Download patch
OLDNEW
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 Handles web page requests for gnubby enrollment. 6 * @fileoverview Handles web page requests for gnubby enrollment.
7 */ 7 */
8 8
9 'use strict'; 9 'use strict';
10 10
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 var responseData = 76 var responseData =
77 makeEnrollResponseData(enrollChallenge, u2fVersion, 77 makeEnrollResponseData(enrollChallenge, u2fVersion,
78 'registrationData', info, 'clientData', browserData); 78 'registrationData', info, 'clientData', browserData);
79 var response = makeU2fSuccessResponse(request, responseData); 79 var response = makeU2fSuccessResponse(request, responseData);
80 sendResponseOnce(sentResponse, closeable, response, sendResponse); 80 sendResponseOnce(sentResponse, closeable, response, sendResponse);
81 } 81 }
82 82
83 closeable = 83 closeable =
84 validateAndBeginEnrollRequest( 84 validateAndBeginEnrollRequest(
85 sender, request, 'registerRequests', 'signRequests', 85 sender, request, 'registerRequests', 'signRequests',
86 sendErrorResponse, sendSuccessResponse); 86 sendErrorResponse, sendSuccessResponse, 'registeredKeys');
87 return closeable; 87 return closeable;
88 } 88 }
89 89
90 /** 90 /**
91 * Validates an enroll request using the given parameters, and, if valid, begins 91 * Validates an enroll request using the given parameters, and, if valid, begins
92 * handling the enroll request. 92 * handling the enroll request. (The enroll request may be modified as a result
93 * of handling it.)
93 * @param {MessageSender} sender The sender of the message. 94 * @param {MessageSender} sender The sender of the message.
94 * @param {Object} request The web page's enroll request. 95 * @param {Object} request The web page's enroll request.
95 * @param {string} enrollChallengesName The name of the enroll challenges value 96 * @param {string} enrollChallengesName The name of the enroll challenges value
96 * in the request. 97 * in the request.
97 * @param {string} signChallengesName The name of the sign challenges value in 98 * @param {string} signChallengesName The name of the sign challenges value in
98 * the request. 99 * the request.
99 * @param {function(ErrorCodes)} errorCb Error callback. 100 * @param {function(ErrorCodes)} errorCb Error callback.
100 * @param {function(string, string, (string|undefined))} successCb Success 101 * @param {function(string, string, (string|undefined))} successCb Success
101 * callback. 102 * callback.
103 * @param {string=} opt_registeredKeysName The name of the registered keys
104 * value in the request.
102 * @return {Closeable} Request handler that should be closed when the browser 105 * @return {Closeable} Request handler that should be closed when the browser
103 * message channel is closed. 106 * message channel is closed.
104 */ 107 */
105 function validateAndBeginEnrollRequest(sender, request, 108 function validateAndBeginEnrollRequest(sender, request,
106 enrollChallengesName, signChallengesName, errorCb, successCb) { 109 enrollChallengesName, signChallengesName, errorCb, successCb,
110 opt_registeredKeysName) {
107 var origin = getOriginFromUrl(/** @type {string} */ (sender.url)); 111 var origin = getOriginFromUrl(/** @type {string} */ (sender.url));
108 if (!origin) { 112 if (!origin) {
109 errorCb(ErrorCodes.BAD_REQUEST); 113 errorCb(ErrorCodes.BAD_REQUEST);
110 return null; 114 return null;
111 } 115 }
112 116
113 if (!isValidEnrollRequest(request, enrollChallengesName, 117 if (!isValidEnrollRequest(request, enrollChallengesName,
114 signChallengesName)) { 118 signChallengesName, opt_registeredKeysName)) {
115 errorCb(ErrorCodes.BAD_REQUEST); 119 errorCb(ErrorCodes.BAD_REQUEST);
116 return null; 120 return null;
117 } 121 }
118 122
119 var enrollChallenges = request[enrollChallengesName]; 123 var enrollChallenges = request[enrollChallengesName];
120 var signChallenges = request[signChallengesName]; 124 var signChallenges;
125 if (opt_registeredKeysName &&
126 request.hasOwnProperty(opt_registeredKeysName)) {
127 // Convert registered keys to sign challenges by adding a challenge value.
128 signChallenges = request[opt_registeredKeysName];
129 for (var i = 0; i < signChallenges.length; i++) {
130 // The actual value doesn't matter, as long as it's a string.
131 signChallenges[i]['challenge'] = '';
132 }
133 } else {
134 signChallenges = request[signChallengesName];
135 }
121 var logMsgUrl = request['logMsgUrl']; 136 var logMsgUrl = request['logMsgUrl'];
122 137
123 var timer = createTimerForRequest( 138 var timer = createTimerForRequest(
124 FACTORY_REGISTRY.getCountdownFactory(), request); 139 FACTORY_REGISTRY.getCountdownFactory(), request);
125 var enroller = new Enroller(timer, origin, errorCb, successCb, 140 var enroller = new Enroller(timer, origin, errorCb, successCb,
126 sender.tlsChannelId, logMsgUrl); 141 sender.tlsChannelId, logMsgUrl);
127 enroller.doEnroll(enrollChallenges, signChallenges); 142 enroller.doEnroll(enrollChallenges, signChallenges, request['appId']);
128 return /** @type {Closeable} */ (enroller); 143 return /** @type {Closeable} */ (enroller);
129 } 144 }
130 145
131 /** 146 /**
132 * Returns whether the request appears to be a valid enroll request. 147 * Returns whether the request appears to be a valid enroll request.
133 * @param {Object} request The request. 148 * @param {Object} request The request.
134 * @param {string} enrollChallengesName The name of the enroll challenges value 149 * @param {string} enrollChallengesName The name of the enroll challenges value
135 * in the request. 150 * in the request.
136 * @param {string} signChallengesName The name of the sign challenges value in 151 * @param {string} signChallengesName The name of the sign challenges value in
137 * the request. 152 * the request.
153 * @param {string=} opt_registeredKeysName The name of the registered keys
154 * value in the request.
138 * @return {boolean} Whether the request appears valid. 155 * @return {boolean} Whether the request appears valid.
139 */ 156 */
140 function isValidEnrollRequest(request, enrollChallengesName, 157 function isValidEnrollRequest(request, enrollChallengesName,
141 signChallengesName) { 158 signChallengesName, opt_registeredKeysName) {
142 if (!request.hasOwnProperty(enrollChallengesName)) 159 if (!request.hasOwnProperty(enrollChallengesName))
143 return false; 160 return false;
144 var enrollChallenges = request[enrollChallengesName]; 161 var enrollChallenges = request[enrollChallengesName];
145 if (!enrollChallenges.length) 162 if (!enrollChallenges.length)
146 return false; 163 return false;
147 if (!isValidEnrollChallengeArray(enrollChallenges)) 164 var hasAppId = request.hasOwnProperty('appId');
165 if (!isValidEnrollChallengeArray(enrollChallenges, !hasAppId))
148 return false; 166 return false;
149 var signChallenges = request[signChallengesName]; 167 var signChallenges = request[signChallengesName];
150 // A missing sign challenge array is ok, in the case the user is not already 168 // A missing sign challenge array is ok, in the case the user is not already
151 // enrolled. 169 // enrolled.
152 if (signChallenges && !isValidSignChallengeArray(signChallenges)) 170 if (signChallenges && !isValidSignChallengeArray(signChallenges, !hasAppId))
153 return false; 171 return false;
172 if (opt_registeredKeysName) {
173 var registeredKeys = request[opt_registeredKeysName];
174 if (registeredKeys &&
175 !isValidRegisteredKeyArray(registeredKeys, !hasAppId)) {
176 return false;
177 }
178 }
154 return true; 179 return true;
155 } 180 }
156 181
157 /** 182 /**
158 * @typedef {{ 183 * @typedef {{
159 * version: (string|undefined), 184 * version: (string|undefined),
160 * challenge: string, 185 * challenge: string,
161 * appId: string 186 * appId: string
162 * }} 187 * }}
163 */ 188 */
164 var EnrollChallenge; 189 var EnrollChallenge;
165 190
166 /** 191 /**
167 * @param {Array.<EnrollChallenge>} enrollChallenges The enroll challenges to 192 * @param {Array.<EnrollChallenge>} enrollChallenges The enroll challenges to
168 * validate. 193 * validate.
194 * @param {boolean} appIdRequired Whether the appId property is required on
195 * each challenge.
169 * @return {boolean} Whether the given array of challenges is a valid enroll 196 * @return {boolean} Whether the given array of challenges is a valid enroll
170 * challenges array. 197 * challenges array.
171 */ 198 */
172 function isValidEnrollChallengeArray(enrollChallenges) { 199 function isValidEnrollChallengeArray(enrollChallenges, appIdRequired) {
173 var seenVersions = {}; 200 var seenVersions = {};
174 for (var i = 0; i < enrollChallenges.length; i++) { 201 for (var i = 0; i < enrollChallenges.length; i++) {
175 var enrollChallenge = enrollChallenges[i]; 202 var enrollChallenge = enrollChallenges[i];
176 var version = enrollChallenge['version']; 203 var version = enrollChallenge['version'];
177 if (!version) { 204 if (!version) {
178 // Version is implicitly V1 if not specified. 205 // Version is implicitly V1 if not specified.
179 version = 'U2F_V1'; 206 version = 'U2F_V1';
180 } 207 }
181 if (version != 'U2F_V1' && version != 'U2F_V2') { 208 if (version != 'U2F_V1' && version != 'U2F_V2') {
182 return false; 209 return false;
183 } 210 }
184 if (seenVersions[version]) { 211 if (seenVersions[version]) {
185 // Each version can appear at most once. 212 // Each version can appear at most once.
186 return false; 213 return false;
187 } 214 }
188 seenVersions[version] = version; 215 seenVersions[version] = version;
189 if (!enrollChallenge['appId']) { 216 if (appIdRequired && !enrollChallenge['appId']) {
190 return false; 217 return false;
191 } 218 }
192 if (!enrollChallenge['challenge']) { 219 if (!enrollChallenge['challenge']) {
193 // The challenge is required. 220 // The challenge is required.
194 return false; 221 return false;
195 } 222 }
196 } 223 }
197 return true; 224 return true;
198 } 225 }
199 226
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 /** 320 /**
294 * Default timeout value in case the caller never provides a valid timeout. 321 * Default timeout value in case the caller never provides a valid timeout.
295 */ 322 */
296 Enroller.DEFAULT_TIMEOUT_MILLIS = 30 * 1000; 323 Enroller.DEFAULT_TIMEOUT_MILLIS = 30 * 1000;
297 324
298 /** 325 /**
299 * Performs an enroll request with the given enroll and sign challenges. 326 * Performs an enroll request with the given enroll and sign challenges.
300 * @param {Array.<EnrollChallenge>} enrollChallenges A set of enroll challenges. 327 * @param {Array.<EnrollChallenge>} enrollChallenges A set of enroll challenges.
301 * @param {Array.<SignChallenge>} signChallenges A set of sign challenges for 328 * @param {Array.<SignChallenge>} signChallenges A set of sign challenges for
302 * existing enrollments for this user and appId. 329 * existing enrollments for this user and appId.
330 * @param {string=} opt_appId The app id for the entire request.
303 */ 331 */
304 Enroller.prototype.doEnroll = function(enrollChallenges, signChallenges) { 332 Enroller.prototype.doEnroll = function(enrollChallenges, signChallenges,
305 var encodedEnrollChallenges = this.encodeEnrollChallenges_(enrollChallenges); 333 opt_appId) {
306 var encodedSignChallenges = encodeSignChallenges(signChallenges); 334 var encodedEnrollChallenges =
335 this.encodeEnrollChallenges_(enrollChallenges, opt_appId);
336 var encodedSignChallenges = encodeSignChallenges(signChallenges, opt_appId);
307 var request = { 337 var request = {
308 type: 'enroll_helper_request', 338 type: 'enroll_helper_request',
309 enrollChallenges: encodedEnrollChallenges, 339 enrollChallenges: encodedEnrollChallenges,
310 signData: encodedSignChallenges, 340 signData: encodedSignChallenges,
311 logMsgUrl: this.logMsgUrl_ 341 logMsgUrl: this.logMsgUrl_
312 }; 342 };
313 if (!this.timer_.expired()) { 343 if (!this.timer_.expired()) {
314 request.timeout = this.timer_.millisecondsUntilExpired() / 1000.0; 344 request.timeout = this.timer_.millisecondsUntilExpired() / 1000.0;
315 request.timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0; 345 request.timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0;
316 } 346 }
317 347
318 // Begin fetching/checking the app ids. 348 // Begin fetching/checking the app ids.
319 var enrollAppIds = []; 349 var enrollAppIds = [];
350 if (opt_appId) {
351 enrollAppIds.push(opt_appId);
352 }
320 for (var i = 0; i < enrollChallenges.length; i++) { 353 for (var i = 0; i < enrollChallenges.length; i++) {
321 enrollAppIds.push(enrollChallenges[i]['appId']); 354 if (enrollChallenges[i].hasOwnProperty('appId')) {
355 enrollAppIds.push(enrollChallenges[i]['appId']);
356 }
357 }
358 // Sanity check
359 if (!enrollAppIds.length) {
360 console.warn(UTIL_fmt('empty enroll app ids?'));
361 this.notifyError_(ErrorCodes.BAD_REQUEST);
362 return;
322 } 363 }
323 var self = this; 364 var self = this;
324 this.checkAppIds_(enrollAppIds, signChallenges, function(result) { 365 this.checkAppIds_(enrollAppIds, signChallenges, function(result) {
325 if (result) { 366 if (result) {
326 self.handler_ = FACTORY_REGISTRY.getRequestHelper().getHandler(request); 367 self.handler_ = FACTORY_REGISTRY.getRequestHelper().getHandler(request);
327 if (self.handler_) { 368 if (self.handler_) {
328 var helperComplete = 369 var helperComplete =
329 /** @type {function(HelperReply)} */ 370 /** @type {function(HelperReply)} */
330 (self.helperComplete_.bind(self)); 371 (self.helperComplete_.bind(self));
331 self.handler_.run(helperComplete); 372 self.handler_.run(helperComplete);
332 } else { 373 } else {
333 self.notifyError_(ErrorCodes.OTHER_ERROR); 374 self.notifyError_(ErrorCodes.OTHER_ERROR);
334 } 375 }
335 } else { 376 } else {
336 self.notifyError_(ErrorCodes.BAD_REQUEST); 377 self.notifyError_(ErrorCodes.BAD_REQUEST);
337 } 378 }
338 }); 379 });
339 }; 380 };
340 381
341 /** 382 /**
342 * Encodes the enroll challenge as an enroll helper challenge. 383 * Encodes the enroll challenge as an enroll helper challenge.
343 * @param {EnrollChallenge} enrollChallenge The enroll challenge to encode. 384 * @param {EnrollChallenge} enrollChallenge The enroll challenge to encode.
385 * @param {string=} opt_appId The app id for the entire request.
344 * @return {EnrollHelperChallenge} The encoded challenge. 386 * @return {EnrollHelperChallenge} The encoded challenge.
345 * @private 387 * @private
346 */ 388 */
347 Enroller.encodeEnrollChallenge_ = function(enrollChallenge) { 389 Enroller.encodeEnrollChallenge_ = function(enrollChallenge, opt_appId) {
348 var encodedChallenge = {}; 390 var encodedChallenge = {};
349 var version; 391 var version;
350 if (enrollChallenge['version']) { 392 if (enrollChallenge['version']) {
351 version = enrollChallenge['version']; 393 version = enrollChallenge['version'];
352 } else { 394 } else {
353 // Version is implicitly V1 if not specified. 395 // Version is implicitly V1 if not specified.
354 version = 'U2F_V1'; 396 version = 'U2F_V1';
355 } 397 }
356 encodedChallenge['version'] = version; 398 encodedChallenge['version'] = version;
357 encodedChallenge['challenge'] = enrollChallenge['challenge']; 399 encodedChallenge['challengeHash'] = enrollChallenge['challenge'];
358 encodedChallenge['appIdHash'] = 400 var appId;
359 B64_encode(sha256HashOfString(enrollChallenge['appId'])); 401 if (enrollChallenge['appId']) {
402 appId = enrollChallenge['appId'];
403 } else {
404 appId = opt_appId;
405 }
406 if (!appId) {
407 // Sanity check. (Other code should fail if it's not set.)
408 console.warn(UTIL_fmt('No appId?'));
409 }
410 encodedChallenge['appIdHash'] = B64_encode(sha256HashOfString(appId));
360 return /** @type {EnrollHelperChallenge} */ (encodedChallenge); 411 return /** @type {EnrollHelperChallenge} */ (encodedChallenge);
361 }; 412 };
362 413
363 /** 414 /**
364 * Encodes the given enroll challenges using this enroller's state. 415 * Encodes the given enroll challenges using this enroller's state.
365 * @param {Array.<EnrollChallenge>} enrollChallenges The enroll challenges. 416 * @param {Array.<EnrollChallenge>} enrollChallenges The enroll challenges.
417 * @param {string=} opt_appId The app id for the entire request.
366 * @return {!Array.<EnrollHelperChallenge>} The encoded enroll challenges. 418 * @return {!Array.<EnrollHelperChallenge>} The encoded enroll challenges.
367 * @private 419 * @private
368 */ 420 */
369 Enroller.prototype.encodeEnrollChallenges_ = function(enrollChallenges) { 421 Enroller.prototype.encodeEnrollChallenges_ = function(enrollChallenges,
422 opt_appId) {
370 var challenges = []; 423 var challenges = [];
371 for (var i = 0; i < enrollChallenges.length; i++) { 424 for (var i = 0; i < enrollChallenges.length; i++) {
372 var enrollChallenge = enrollChallenges[i]; 425 var enrollChallenge = enrollChallenges[i];
373 var version = enrollChallenge.version; 426 var version = enrollChallenge.version;
374 if (!version) { 427 if (!version) {
375 // Version is implicitly V1 if not specified. 428 // Version is implicitly V1 if not specified.
376 version = 'U2F_V1'; 429 version = 'U2F_V1';
377 } 430 }
378 431
379 if (version == 'U2F_V2') { 432 if (version == 'U2F_V2') {
380 var modifiedChallenge = {}; 433 var modifiedChallenge = {};
381 for (var k in enrollChallenge) { 434 for (var k in enrollChallenge) {
382 modifiedChallenge[k] = enrollChallenge[k]; 435 modifiedChallenge[k] = enrollChallenge[k];
383 } 436 }
384 // V2 enroll responses contain signatures over a browser data object, 437 // V2 enroll responses contain signatures over a browser data object,
385 // which we're constructing here. The browser data object contains, among 438 // which we're constructing here. The browser data object contains, among
386 // other things, the server challenge. 439 // other things, the server challenge.
387 var serverChallenge = enrollChallenge['challenge']; 440 var serverChallenge = enrollChallenge['challenge'];
388 var browserData = makeEnrollBrowserData( 441 var browserData = makeEnrollBrowserData(
389 serverChallenge, this.origin_, this.tlsChannelId_); 442 serverChallenge, this.origin_, this.tlsChannelId_);
390 // Replace the challenge with the hash of the browser data. 443 // Replace the challenge with the hash of the browser data.
391 modifiedChallenge['challenge'] = 444 modifiedChallenge['challenge'] =
392 B64_encode(sha256HashOfString(browserData)); 445 B64_encode(sha256HashOfString(browserData));
393 this.browserData_[version] = 446 this.browserData_[version] =
394 B64_encode(UTIL_StringToBytes(browserData)); 447 B64_encode(UTIL_StringToBytes(browserData));
395 challenges.push(Enroller.encodeEnrollChallenge_( 448 challenges.push(Enroller.encodeEnrollChallenge_(
396 /** @type {EnrollChallenge} */ (modifiedChallenge))); 449 /** @type {EnrollChallenge} */ (modifiedChallenge), opt_appId));
397 } else { 450 } else {
398 challenges.push(Enroller.encodeEnrollChallenge_(enrollChallenge)); 451 challenges.push(
452 Enroller.encodeEnrollChallenge_(enrollChallenge, opt_appId));
399 } 453 }
400 } 454 }
401 return challenges; 455 return challenges;
402 }; 456 };
403 457
404 /** 458 /**
405 * Checks the app ids associated with this enroll request, and calls a callback 459 * Checks the app ids associated with this enroll request, and calls a callback
406 * with the result of the check. 460 * with the result of the check.
407 * @param {!Array.<string>} enrollAppIds The app ids in the enroll challenge 461 * @param {!Array.<string>} enrollAppIds The app ids in the enroll challenge
408 * portion of the enroll request. 462 * portion of the enroll request.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash 552 // For U2F_V2, the challenge sent to the gnubby is modified to be the hash
499 // of the browser data. Include the browser data. 553 // of the browser data. Include the browser data.
500 browserData = this.browserData_[reply.version]; 554 browserData = this.browserData_[reply.version];
501 } 555 }
502 556
503 this.notifySuccess_(/** @type {string} */ (reply.version), 557 this.notifySuccess_(/** @type {string} */ (reply.version),
504 /** @type {string} */ (reply.enrollData), 558 /** @type {string} */ (reply.enrollData),
505 browserData); 559 browserData);
506 } 560 }
507 }; 561 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/cryptotoken/devicestatuscodes.js ('k') | chrome/browser/resources/cryptotoken/gnubby-u2f.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698