| 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 Does common handling for requests coming from web pages and | 6 * @fileoverview Does common handling for requests coming from web pages and |
| 7 * routes them to the provided handler. | 7 * routes them to the provided handler. |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 /** | 10 /** |
| 11 * FIDO U2F Javascript API Version | 11 * FIDO U2F Javascript API Version |
| 12 * @const | 12 * @const |
| 13 * @type {number} | 13 * @type {number} |
| 14 */ | 14 */ |
| 15 var JS_API_VERSION = 1.1; | 15 var JS_API_VERSION = 1.1; |
| 16 | 16 |
| 17 /** | 17 /** |
| 18 * Gets the scheme + origin from a web url. | 18 * Gets the scheme + origin from a web url. |
| 19 * @param {string} url Input url | 19 * @param {string} url Input url |
| 20 * @return {?string} Scheme and origin part if url parses | 20 * @return {?string} Scheme and origin part if url parses |
| 21 */ | 21 */ |
| 22 function getOriginFromUrl(url) { | 22 function getOriginFromUrl(url) { |
| 23 var re = new RegExp('^(https?://)[^/]*/?'); | 23 var re = new RegExp('^(https?://)[^/]*/?'); |
| 24 var originarray = re.exec(url); | 24 var originarray = re.exec(url); |
| 25 if (originarray == null) return originarray; | 25 if (originarray == null) |
| 26 return originarray; |
| 26 var origin = originarray[0]; | 27 var origin = originarray[0]; |
| 27 while (origin.charAt(origin.length - 1) == '/') { | 28 while (origin.charAt(origin.length - 1) == '/') { |
| 28 origin = origin.substring(0, origin.length - 1); | 29 origin = origin.substring(0, origin.length - 1); |
| 29 } | 30 } |
| 30 if (origin == 'http:' || origin == 'https:') | 31 if (origin == 'http:' || origin == 'https:') |
| 31 return null; | 32 return null; |
| 32 return origin; | 33 return origin; |
| 33 } | 34 } |
| 34 | 35 |
| 35 /** | 36 /** |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 88 | 89 |
| 89 /** | 90 /** |
| 90 * Returns whether the array of SignChallenges appears to be valid. | 91 * Returns whether the array of SignChallenges appears to be valid. |
| 91 * @param {Array<SignChallenge>} signChallenges The array of sign challenges. | 92 * @param {Array<SignChallenge>} signChallenges The array of sign challenges. |
| 92 * @param {boolean} challengeValueRequired Whether each challenge object | 93 * @param {boolean} challengeValueRequired Whether each challenge object |
| 93 * requires a challenge value. | 94 * requires a challenge value. |
| 94 * @param {boolean} appIdRequired Whether the appId property is required on | 95 * @param {boolean} appIdRequired Whether the appId property is required on |
| 95 * each challenge. | 96 * each challenge. |
| 96 * @return {boolean} Whether the array appears valid. | 97 * @return {boolean} Whether the array appears valid. |
| 97 */ | 98 */ |
| 98 function isValidSignChallengeArray(signChallenges, challengeValueRequired, | 99 function isValidSignChallengeArray( |
| 99 appIdRequired) { | 100 signChallenges, challengeValueRequired, appIdRequired) { |
| 100 for (var i = 0; i < signChallenges.length; i++) { | 101 for (var i = 0; i < signChallenges.length; i++) { |
| 101 var incomingChallenge = signChallenges[i]; | 102 var incomingChallenge = signChallenges[i]; |
| 102 if (challengeValueRequired && | 103 if (challengeValueRequired && |
| 103 !incomingChallenge.hasOwnProperty('challenge')) | 104 !incomingChallenge.hasOwnProperty('challenge')) |
| 104 return false; | 105 return false; |
| 105 if (!isValidRegisteredKey(incomingChallenge, appIdRequired)) { | 106 if (!isValidRegisteredKey(incomingChallenge, appIdRequired)) { |
| 106 return false; | 107 return false; |
| 107 } | 108 } |
| 108 } | 109 } |
| 109 return true; | 110 return true; |
| 110 } | 111 } |
| 111 | 112 |
| 112 /** | 113 /** |
| 113 * @param {Object} request Request object | 114 * @param {Object} request Request object |
| 114 * @param {MessageSender} sender Sender frame | 115 * @param {MessageSender} sender Sender frame |
| 115 * @param {Function} sendResponse Response callback | 116 * @param {Function} sendResponse Response callback |
| 116 * @return {?Closeable} Optional handler object that should be closed when port | 117 * @return {?Closeable} Optional handler object that should be closed when port |
| 117 * closes | 118 * closes |
| 118 */ | 119 */ |
| 119 function handleWebPageRequest(request, sender, sendResponse) { | 120 function handleWebPageRequest(request, sender, sendResponse) { |
| 120 switch (request.type) { | 121 switch (request.type) { |
| 121 case MessageTypes.U2F_REGISTER_REQUEST: | 122 case MessageTypes.U2F_REGISTER_REQUEST: |
| 122 return handleU2fEnrollRequest(sender, request, sendResponse); | 123 return handleU2fEnrollRequest(sender, request, sendResponse); |
| 123 | 124 |
| 124 case MessageTypes.U2F_SIGN_REQUEST: | 125 case MessageTypes.U2F_SIGN_REQUEST: |
| 125 return handleU2fSignRequest(sender, request, sendResponse); | 126 return handleU2fSignRequest(sender, request, sendResponse); |
| 126 | 127 |
| 127 case MessageTypes.U2F_GET_API_VERSION_REQUEST: | 128 case MessageTypes.U2F_GET_API_VERSION_REQUEST: |
| 128 sendResponse( | 129 sendResponse(makeU2fGetApiVersionResponse( |
| 129 makeU2fGetApiVersionResponse(request, JS_API_VERSION, | 130 request, JS_API_VERSION, MessageTypes.U2F_GET_API_VERSION_RESPONSE)); |
| 130 MessageTypes.U2F_GET_API_VERSION_RESPONSE)); | |
| 131 return null; | 131 return null; |
| 132 | 132 |
| 133 default: | 133 default: |
| 134 sendResponse( | 134 sendResponse(makeU2fErrorResponse( |
| 135 makeU2fErrorResponse(request, ErrorCodes.BAD_REQUEST, undefined, | 135 request, ErrorCodes.BAD_REQUEST, undefined, |
| 136 MessageTypes.U2F_REGISTER_RESPONSE)); | 136 MessageTypes.U2F_REGISTER_RESPONSE)); |
| 137 return null; | 137 return null; |
| 138 } | 138 } |
| 139 } | 139 } |
| 140 | 140 |
| 141 /** | 141 /** |
| 142 * Makes a response to a request. | 142 * Makes a response to a request. |
| 143 * @param {Object} request The request to make a response to. | 143 * @param {Object} request The request to make a response to. |
| 144 * @param {string} responseSuffix How to name the response's type. | 144 * @param {string} responseSuffix How to name the response's type. |
| 145 * @param {string=} opt_defaultType The default response type, if none is | 145 * @param {string=} opt_defaultType The default response type, if none is |
| 146 * present in the request. | 146 * present in the request. |
| 147 * @return {Object} The response object. | 147 * @return {Object} The response object. |
| 148 */ | 148 */ |
| 149 function makeResponseForRequest(request, responseSuffix, opt_defaultType) { | 149 function makeResponseForRequest(request, responseSuffix, opt_defaultType) { |
| 150 var type; | 150 var type; |
| 151 if (request && request.type) { | 151 if (request && request.type) { |
| 152 type = request.type.replace(/_request$/, responseSuffix); | 152 type = request.type.replace(/_request$/, responseSuffix); |
| 153 } else { | 153 } else { |
| 154 type = opt_defaultType; | 154 type = opt_defaultType; |
| 155 } | 155 } |
| 156 var reply = { 'type': type }; | 156 var reply = {'type': type}; |
| 157 if (request && request.requestId) { | 157 if (request && request.requestId) { |
| 158 reply.requestId = request.requestId; | 158 reply.requestId = request.requestId; |
| 159 } | 159 } |
| 160 return reply; | 160 return reply; |
| 161 } | 161 } |
| 162 | 162 |
| 163 /** | 163 /** |
| 164 * Makes a response to a U2F request with an error code. | 164 * Makes a response to a U2F request with an error code. |
| 165 * @param {Object} request The request to make a response to. | 165 * @param {Object} request The request to make a response to. |
| 166 * @param {ErrorCodes} code The error code to return. | 166 * @param {ErrorCodes} code The error code to return. |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 * @param {!string} type A string representing the "type" of this browser data | 292 * @param {!string} type A string representing the "type" of this browser data |
| 293 * object. | 293 * object. |
| 294 * @param {!string} serverChallenge The server's challenge, as a base64- | 294 * @param {!string} serverChallenge The server's challenge, as a base64- |
| 295 * encoded string. | 295 * encoded string. |
| 296 * @param {!string} origin The server's origin, as seen by the browser. | 296 * @param {!string} origin The server's origin, as seen by the browser. |
| 297 * @param {Object|string|undefined} opt_tlsChannelId TLS Channel Id | 297 * @param {Object|string|undefined} opt_tlsChannelId TLS Channel Id |
| 298 * @return {string} A string representation of the browser data object. | 298 * @return {string} A string representation of the browser data object. |
| 299 */ | 299 */ |
| 300 function makeBrowserData(type, serverChallenge, origin, opt_tlsChannelId) { | 300 function makeBrowserData(type, serverChallenge, origin, opt_tlsChannelId) { |
| 301 var browserData = { | 301 var browserData = { |
| 302 'typ' : type, | 302 'typ': type, |
| 303 'challenge' : serverChallenge, | 303 'challenge': serverChallenge, |
| 304 'origin' : origin | 304 'origin': origin |
| 305 }; | 305 }; |
| 306 if (BROWSER_SUPPORTS_TLS_CHANNEL_ID) { | 306 if (BROWSER_SUPPORTS_TLS_CHANNEL_ID) { |
| 307 browserData['cid_pubkey'] = tlsChannelIdValue(opt_tlsChannelId); | 307 browserData['cid_pubkey'] = tlsChannelIdValue(opt_tlsChannelId); |
| 308 } | 308 } |
| 309 return JSON.stringify(browserData); | 309 return JSON.stringify(browserData); |
| 310 } | 310 } |
| 311 | 311 |
| 312 /** | 312 /** |
| 313 * Creates a browser data object for an enroll request with the given values. | 313 * Creates a browser data object for an enroll request with the given values. |
| 314 * @param {!string} serverChallenge The server's challenge, as a base64- | 314 * @param {!string} serverChallenge The server's challenge, as a base64- |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 357 * @param {string|undefined} opt_defaultChallenge A default sign challenge | 357 * @param {string|undefined} opt_defaultChallenge A default sign challenge |
| 358 * value, if a request does not provide one. | 358 * value, if a request does not provide one. |
| 359 * @param {string=} opt_defaultAppId The app id to use for each challenge, if | 359 * @param {string=} opt_defaultAppId The app id to use for each challenge, if |
| 360 * the challenge contains none. | 360 * the challenge contains none. |
| 361 * @param {function(string, string): string=} opt_challengeHashFunction | 361 * @param {function(string, string): string=} opt_challengeHashFunction |
| 362 * A function that produces, from a key handle and a raw challenge, a hash | 362 * A function that produces, from a key handle and a raw challenge, a hash |
| 363 * of the raw challenge. If none is provided, a default hash function is | 363 * of the raw challenge. If none is provided, a default hash function is |
| 364 * used. | 364 * used. |
| 365 * @return {!Array<SignHelperChallenge>} The sign challenges, encoded. | 365 * @return {!Array<SignHelperChallenge>} The sign challenges, encoded. |
| 366 */ | 366 */ |
| 367 function encodeSignChallenges(signChallenges, opt_defaultChallenge, | 367 function encodeSignChallenges( |
| 368 opt_defaultAppId, opt_challengeHashFunction) { | 368 signChallenges, opt_defaultChallenge, opt_defaultAppId, |
| 369 opt_challengeHashFunction) { |
| 369 function encodedSha256(keyHandle, challenge) { | 370 function encodedSha256(keyHandle, challenge) { |
| 370 return B64_encode(sha256HashOfString(challenge)); | 371 return B64_encode(sha256HashOfString(challenge)); |
| 371 } | 372 } |
| 372 var challengeHashFn = opt_challengeHashFunction || encodedSha256; | 373 var challengeHashFn = opt_challengeHashFunction || encodedSha256; |
| 373 var encodedSignChallenges = []; | 374 var encodedSignChallenges = []; |
| 374 if (signChallenges) { | 375 if (signChallenges) { |
| 375 for (var i = 0; i < signChallenges.length; i++) { | 376 for (var i = 0; i < signChallenges.length; i++) { |
| 376 var challenge = signChallenges[i]; | 377 var challenge = signChallenges[i]; |
| 377 var keyHandle = challenge['keyHandle']; | 378 var keyHandle = challenge['keyHandle']; |
| 378 var challengeValue; | 379 var challengeValue; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 'type': 'sign_helper_request', | 413 'type': 'sign_helper_request', |
| 413 'signData': challenges, | 414 'signData': challenges, |
| 414 'timeout': opt_timeoutSeconds || 0, | 415 'timeout': opt_timeoutSeconds || 0, |
| 415 'timeoutSeconds': opt_timeoutSeconds || 0 | 416 'timeoutSeconds': opt_timeoutSeconds || 0 |
| 416 }; | 417 }; |
| 417 if (opt_logMsgUrl !== undefined) { | 418 if (opt_logMsgUrl !== undefined) { |
| 418 request.logMsgUrl = opt_logMsgUrl; | 419 request.logMsgUrl = opt_logMsgUrl; |
| 419 } | 420 } |
| 420 return request; | 421 return request; |
| 421 } | 422 } |
| OLD | NEW |