Commit 5fcf81dd authored by Chris Lu's avatar Chris Lu Committed by Commit Bot

[ios] Split WebFrame JavaScript message payload

Separate function name and parameters from the rest of the Message payload.

This change encrypts the function name and its parameters in a separate payload
from the messageId and replyWithResult values. __gCrWeb.message.routeMessage() is
then passed two dictionaries, each containing an encrypted payload and its
initialization vector.

Both payloads are decrypted and their properties verified in executeMessage_().
This will allow for the function name and parameters to be dropped when
forwarding to a child frame, while still providing enough details for the
child frame to respond to the native side that it received the message.

Bug: 994968
Change-Id: I659d88b8119b2eba2b125d8c30cbea88485c88f1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1759204Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Reviewed-by: default avatarMike Dougherty <michaeldo@chromium.org>
Commit-Queue: Chris Lu <thegreenfrog@chromium.org>
Cr-Commit-Position: refs/heads/master@{#694992}
parent fd46f03c
...@@ -238,11 +238,17 @@ var callGCrWebFunction_ = function(functionPath, parameters) { ...@@ -238,11 +238,17 @@ var callGCrWebFunction_ = function(functionPath, parameters) {
} }
/** /**
* Decrypts and executes the function specified in |payload|. * Decrypts and executes the function specified in |functionPayload|.
* @param {!string} payload The encrypted message payload. * @param {Object} encryptedMessageDetails JSON containing encrypted
* @param {!string} iv The initialization vector used to encrypt the |payload|. * information about the message and the initialization vector to decrypt
* the information.
* @param {!Object} encryptedFunctionDetails JSON containing encrypted
* information about the function and its parameters and the initialization
* vector to decrypt the information. If null, won't execute any call, but
* will respond to the native call if specified in |encryptedMessageDetails|.
*/ */
var executeMessage_ = function(payload, iv) { var executeMessage_ = function(encryptedMessageDetails,
encryptedFunctionDetails) {
if (!frameSymmetricKey_) { if (!frameSymmetricKey_) {
// Payload cannot be decrypted without a key. This message could be spam or // Payload cannot be decrypted without a key. This message could be spam or
// sent by the native application by mistake. // sent by the native application by mistake.
...@@ -250,43 +256,84 @@ var executeMessage_ = function(payload, iv) { ...@@ -250,43 +256,84 @@ var executeMessage_ = function(payload, iv) {
} }
// Decode the base64 payload. // Decode the base64 payload.
var encryptedFunctionArray = var encryptedMessageArray = new Uint8Array(Array.from(
new Uint8Array(Array.from(atob(payload)).map(function(a) { atob(encryptedMessageDetails['payload'])).map(function(a) {
return a.charCodeAt(0); return a.charCodeAt(0);
})); }));
// Decode the base64 initialization buffer. // Decode the base64 initialization buffer.
var ivbuf = new Uint8Array(Array.from(atob(iv)).map(function(a) { var messageIvbuf = new Uint8Array(Array.from(
atob(encryptedMessageDetails['iv'])).map(function(a) {
return a.charCodeAt(0); return a.charCodeAt(0);
})); }));
var messageAlgorithm = {'name': 'AES-GCM', iv: messageIvbuf};
var algorithm = {'name': 'AES-GCM', iv: ivbuf};
getFrameSymmetricKey_(function(frameKey) { getFrameSymmetricKey_(function(frameKey) {
window.crypto.subtle.decrypt(algorithm, frameKey, encryptedFunctionArray) window.crypto.subtle.decrypt(
.then(function(decrypted) { messageAlgorithm, frameKey, encryptedMessageArray)
var callJSON = new TextDecoder().decode(new Uint8Array(decrypted)); .then(function(decryptedMessagePayload) {
var callDict = JSON.parse(callJSON); var messageJSONString = new TextDecoder().decode(
new Uint8Array(decryptedMessagePayload));
var messageDict = JSON.parse(messageJSONString);
// Verify that message id is valid. // Verify that message id is valid.
if (!Number.isInteger(callDict['messageId']) || if (!Number.isInteger(messageDict['messageId']) ||
callDict['messageId'] <= lastReceivedMessageId_) { messageDict['messageId'] <= lastReceivedMessageId_) {
return; return;
} }
// Check that a function name and parameters are specified. lastReceivedMessageId_ = messageDict['messageId'];
if (typeof callDict['functionName'] !== 'string' ||
callDict['functionName'].length < 1 || // Return early if the function payload was dropped.
!Array.isArray(callDict['parameters'])) { if (!encryptedFunctionDetails) {
if (typeof messageDict['replyWithResult'] === 'boolean' &&
messageDict['replyWithResult']) {
replyWithResult_(messageDict['messageId'], null);
}
return; return;
} }
lastReceivedMessageId_ = callDict['messageId']; // Decode the base64 payload.
var result = var encryptedFunctionArray = new Uint8Array(Array.from(
callGCrWebFunction_(callDict['functionName'], callDict['parameters']); atob(encryptedFunctionDetails['payload'])).map(
if (typeof callDict['replyWithResult'] === 'boolean' && function(a) {
callDict['replyWithResult']) { return a.charCodeAt(0);
replyWithResult_(callDict['messageId'], result); }));
}
// Decode the base64 initialization buffer.
var functionIvbuf = new Uint8Array(Array.from(
atob(encryptedFunctionDetails['iv'])).map(
function(a) {
return a.charCodeAt(0);
}));
var additionalData = new Uint8Array(Array.from(
messageDict['messageId'].toString()).map(
function(a) {
return a.charCodeAt(0);
}));
var functionAlgorithm = {'name': 'AES-GCM',
iv: functionIvbuf,
additionalData: additionalData};
window.crypto.subtle.decrypt(
functionAlgorithm, frameKey, encryptedFunctionArray)
.then(function(decryptedFunctionPayload) {
var functionJSONPayload = new TextDecoder().decode(
new Uint8Array(decryptedFunctionPayload));
var functionDict = JSON.parse(functionJSONPayload);
let functionName = functionDict['functionName'];
let parameters = functionDict['parameters'];
var result = null;
if (typeof functionName === 'string' && functionName.length >= 1
&& Array.isArray(parameters)) {
result = callGCrWebFunction_(functionName, parameters);
}
if (typeof messageDict['replyWithResult'] === 'boolean'
&& messageDict['replyWithResult']) {
replyWithResult_(messageDict['messageId'], result);
}
});
}); });
}); });
}; };
...@@ -316,19 +363,24 @@ __gCrWeb.message['getFrameId'] = function() { ...@@ -316,19 +363,24 @@ __gCrWeb.message['getFrameId'] = function() {
* Routes an encrypted message to the targeted frame. Once the target frame is * Routes an encrypted message to the targeted frame. Once the target frame is
* found, the |payload| will be decrypted and executed. This function is called * found, the |payload| will be decrypted and executed. This function is called
* by the native code. * by the native code.
* @param {!string} payload The encrypted message payload. * @param {!Object} encryptedMessageDetails JSON representing a dictionary
* @param {!string} iv The initialization vector used to encrypt the |payload|. * containing encrypted information about the message and the initialization
* vector to decrypt the information.
* @param {!Object} encryptedFunctionDetails JSON representing a dictionary
* containing encrypted information about the function to call and the
* parameters to pass and the initialization vector to decrypt the information.
* @param {!string} target_frame_id The |frameId_| of the frame which should * @param {!string} target_frame_id The |frameId_| of the frame which should
* process the |payload|. * process the |payload|.
*/ */
__gCrWeb.message['routeMessage'] = function(payload, iv, target_frame_id) { __gCrWeb.message['routeMessage'] = function(encryptedMessageDetails,
encryptedFunctionDetails, target_frame_id) {
if (!isFrameMessagingSupported_()) { if (!isFrameMessagingSupported_()) {
// API is unsupported. // API is unsupported.
return; return;
} }
if (target_frame_id === __gCrWeb.message['getFrameId']()) { if (target_frame_id === __gCrWeb.message['getFrameId']()) {
executeMessage_(payload, iv); executeMessage_(encryptedMessageDetails, encryptedFunctionDetails);
return; return;
} }
...@@ -337,8 +389,8 @@ __gCrWeb.message['routeMessage'] = function(payload, iv, target_frame_id) { ...@@ -337,8 +389,8 @@ __gCrWeb.message['routeMessage'] = function(payload, iv, target_frame_id) {
window.frames[i].postMessage( window.frames[i].postMessage(
{ {
type: 'org.chromium.encryptedMessage', type: 'org.chromium.encryptedMessage',
payload: payload, message_payload: encryptedMessageDetails,
iv: iv, function_payload: encryptedFunctionDetails,
target_frame_id: target_frame_id target_frame_id: target_frame_id
}, },
'*' '*'
......
...@@ -37,12 +37,12 @@ window.addEventListener('message', function(message) { ...@@ -37,12 +37,12 @@ window.addEventListener('message', function(message) {
__gCrWeb.message['getExistingFrames'](); __gCrWeb.message['getExistingFrames']();
} else if (payload.hasOwnProperty('type') && } else if (payload.hasOwnProperty('type') &&
payload.type == 'org.chromium.encryptedMessage') { payload.type == 'org.chromium.encryptedMessage') {
if (payload.hasOwnProperty('payload') && if (payload.hasOwnProperty('message_payload') &&
payload.hasOwnProperty('iv') && payload.hasOwnProperty('function_payload') &&
payload.hasOwnProperty('target_frame_id')) { payload.hasOwnProperty('target_frame_id')) {
__gCrWeb.message['routeMessage']( __gCrWeb.message['routeMessage'](
payload['payload'], payload['message_payload'],
payload['iv'], payload['function_payload'],
payload['target_frame_id'] payload['target_frame_id']
); );
} }
......
...@@ -70,6 +70,11 @@ class WebFrameImpl : public WebFrame, public web::WebStateObserver { ...@@ -70,6 +70,11 @@ class WebFrameImpl : public WebFrame, public web::WebStateObserver {
void DetachFromWebState(); void DetachFromWebState();
// Returns the script command name to use for this WebFrame. // Returns the script command name to use for this WebFrame.
const std::string GetScriptCommandPrefix(); const std::string GetScriptCommandPrefix();
// Encrypts |payload| and returns a JSON string of a dictionary containing
// the encrypted metadata and its initialization vector. If encryption fails,
// an empty string will be returned.
const std::string EncryptPayload(base::DictionaryValue payload,
const std::string& additiona_data);
// A structure to store the callbacks associated with the // A structure to store the callbacks associated with the
// |CallJavaScriptFunction| requests. // |CallJavaScriptFunction| requests.
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/base64.h" #include "base/base64.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -85,6 +86,36 @@ bool WebFrameImpl::CanCallJavaScriptFunction() const { ...@@ -85,6 +86,36 @@ bool WebFrameImpl::CanCallJavaScriptFunction() const {
return is_main_frame_ || frame_key_; return is_main_frame_ || frame_key_;
} }
const std::string WebFrameImpl::EncryptPayload(
base::DictionaryValue payload,
const std::string& additiona_data) {
crypto::Aead aead(crypto::Aead::AES_256_GCM);
aead.Init(&frame_key_->key());
std::string payload_json;
base::JSONWriter::Write(payload, &payload_json);
std::string payload_iv;
crypto::RandBytes(base::WriteInto(&payload_iv, aead.NonceLength() + 1),
aead.NonceLength());
std::string payload_ciphertext;
if (!aead.Seal(payload_json, payload_iv, additiona_data,
&payload_ciphertext)) {
LOG(ERROR) << "Error sealing message payload for WebFrame.";
return std::string();
}
std::string encoded_payload_iv;
base::Base64Encode(payload_iv, &encoded_payload_iv);
std::string encoded_payload;
base::Base64Encode(payload_ciphertext, &encoded_payload);
std::string payload_string;
base::DictionaryValue payload_dict;
payload_dict.SetKey("payload", base::Value(encoded_payload));
payload_dict.SetKey("iv", base::Value(encoded_payload_iv));
base::JSONWriter::Write(payload_dict, &payload_string);
return payload_string;
}
bool WebFrameImpl::CallJavaScriptFunction( bool WebFrameImpl::CallJavaScriptFunction(
const std::string& name, const std::string& name,
const std::vector<base::Value>& parameters, const std::vector<base::Value>& parameters,
...@@ -101,36 +132,28 @@ bool WebFrameImpl::CallJavaScriptFunction( ...@@ -101,36 +132,28 @@ bool WebFrameImpl::CallJavaScriptFunction(
reply_with_result); reply_with_result);
} }
base::DictionaryValue message; base::DictionaryValue message_payload;
message.SetKey("messageId", base::Value(message_id)); message_payload.SetKey("messageId", base::Value(message_id));
message.SetKey("replyWithResult", base::Value(reply_with_result)); message_payload.SetKey("replyWithResult", base::Value(reply_with_result));
message.SetKey("functionName", base::Value(name)); const std::string& encrypted_message_json =
base::ListValue parameters_value(parameters); EncryptPayload(std::move(message_payload), std::string());
message.SetKey("parameters", std::move(parameters_value));
std::string json;
base::JSONWriter::Write(message, &json);
crypto::Aead aead(crypto::Aead::AES_256_GCM); base::DictionaryValue function_payload;
aead.Init(&frame_key_->key()); function_payload.SetKey("functionName", base::Value(name));
base::ListValue parameters_value(parameters);
std::string iv; function_payload.SetKey("parameters", std::move(parameters_value));
crypto::RandBytes(base::WriteInto(&iv, aead.NonceLength() + 1), const std::string& encrypted_function_json = EncryptPayload(
aead.NonceLength()); std::move(function_payload), base::NumberToString(message_id));
std::string ciphertext; if (encrypted_message_json.empty() || encrypted_function_json.empty()) {
if (!aead.Seal(json, iv, /*additional_data=*/nullptr, &ciphertext)) { // Sealing the payload failed.
LOG(ERROR) << "Error sealing message for WebFrame.";
return false; return false;
} }
std::string encoded_iv; std::string script =
base::Base64Encode(iv, &encoded_iv); base::StringPrintf("__gCrWeb.message.routeMessage(%s, %s, '%s')",
std::string encoded_message; encrypted_message_json.c_str(),
base::Base64Encode(ciphertext, &encoded_message); encrypted_function_json.c_str(), frame_id_.c_str());
std::string script = base::StringPrintf(
"__gCrWeb.message.routeMessage('%s', '%s', '%s')",
encoded_message.c_str(), encoded_iv.c_str(), frame_id_.c_str());
GetWebState()->ExecuteJavaScript(base::UTF8ToUTF16(script)); GetWebState()->ExecuteJavaScript(base::UTF8ToUTF16(script));
return true; return true;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#import "base/strings/sys_string_conversions.h" #import "base/strings/sys_string_conversions.h"
#include "base/test/ios/wait_util.h" #include "base/test/ios/wait_util.h"
#include "base/values.h" #include "base/values.h"
...@@ -39,8 +40,10 @@ std::unique_ptr<SymmetricKey> CreateKey() { ...@@ -39,8 +40,10 @@ std::unique_ptr<SymmetricKey> CreateKey() {
} }
struct RouteMessageParameters { struct RouteMessageParameters {
NSString* encoded_function_json = nil; NSString* encoded_message_payload = nil;
NSString* encoded_iv = nil; NSString* encoded_message_iv = nil;
NSString* encoded_function_payload = nil;
NSString* encoded_function_iv = nil;
NSString* frame_id = nil; NSString* frame_id = nil;
}; };
...@@ -48,25 +51,36 @@ RouteMessageParameters ParametersFromFunctionCallString( ...@@ -48,25 +51,36 @@ RouteMessageParameters ParametersFromFunctionCallString(
NSString* function_call) { NSString* function_call) {
NSRange parameters_start = [function_call rangeOfString:@"("]; NSRange parameters_start = [function_call rangeOfString:@"("];
NSRange parameters_end = [function_call rangeOfString:@")"]; NSRange parameters_end = [function_call rangeOfString:@")"];
NSString* parameter_string = [function_call NSMutableString* parameter_string = [[function_call
substringWithRange:NSMakeRange(parameters_start.location + 1, substringWithRange:NSMakeRange(parameters_start.location + 1,
parameters_end.location - parameters_end.location -
parameters_start.location - 1)]; parameters_start.location - 1)]
NSArray* parameters = [parameter_string componentsSeparatedByString:@","]; mutableCopy];
// Create array string and replace single quotes with double quotes in
// preparation for JSON serialization.
[parameter_string insertString:@"[" atIndex:0];
[parameter_string appendString:@"]"];
NSString* final_string =
[parameter_string stringByReplacingOccurrencesOfString:@"'"
withString:@"\""];
NSData* data = [final_string dataUsingEncoding:NSUTF8StringEncoding];
NSError* error = nil;
NSArray* jsonArray =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers |
NSJSONReadingMutableLeaves
error:&error];
RouteMessageParameters parsed_params; RouteMessageParameters parsed_params;
if (parameters.count == 3) { if (jsonArray.count == 3 && !error) {
NSMutableCharacterSet* trim_characters_set = parsed_params.encoded_message_iv = jsonArray[0][@"iv"];
[NSMutableCharacterSet whitespaceCharacterSet]; parsed_params.encoded_message_payload = jsonArray[0][@"payload"];
[trim_characters_set addCharactersInString:@"'"]; parsed_params.encoded_function_iv = jsonArray[1][@"iv"];
parsed_params.encoded_function_payload = jsonArray[1][@"payload"];
parsed_params.encoded_function_json = parsed_params.frame_id = jsonArray[2];
[parameters[0] stringByTrimmingCharactersInSet:trim_characters_set];
parsed_params.encoded_iv =
[parameters[1] stringByTrimmingCharactersInSet:trim_characters_set];
parsed_params.frame_id =
[parameters[2] stringByTrimmingCharactersInSet:trim_characters_set];
} }
return parsed_params; return parsed_params;
} }
...@@ -160,21 +174,33 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunction) { ...@@ -160,21 +174,33 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunction) {
RouteMessageParameters params = ParametersFromFunctionCallString(last_script); RouteMessageParameters params = ParametersFromFunctionCallString(last_script);
// Verify that the message is a properly base64 encoded string. // Verify that the message and function payload are properly base64 encoded
std::string decoded_message; // strings.
std::string decoded_function_payload;
EXPECT_TRUE(base::Base64Decode( EXPECT_TRUE(base::Base64Decode(
base::SysNSStringToUTF8(params.encoded_function_json), &decoded_message)); base::SysNSStringToUTF8(params.encoded_function_payload),
// Verify the message does not contain the plaintext function name or &decoded_function_payload));
std::string decoded_message_payload;
EXPECT_TRUE(base::Base64Decode(
base::SysNSStringToUTF8(params.encoded_message_payload),
&decoded_message_payload));
// Verify the function does not contain the plaintext function name or
// parameters. // parameters.
EXPECT_FALSE([base::SysUTF8ToNSString(decoded_message) EXPECT_FALSE([base::SysUTF8ToNSString(decoded_function_payload)
containsString:@"functionName"]); containsString:@"functionName"]);
EXPECT_FALSE([base::SysUTF8ToNSString(decoded_message) EXPECT_FALSE([base::SysUTF8ToNSString(decoded_function_payload)
containsString:@"plaintextParam"]); containsString:@"plaintextParam"]);
std::string iv_string = base::SysNSStringToUTF8(params.encoded_iv); // Verify that the initialization vector is a properly base64 encoded string
std::string decoded_iv; // for both payloads.
// Verify that the initialization vector is a properly base64 encoded string. std::string function_iv_string =
EXPECT_TRUE(base::Base64Decode(iv_string, &decoded_iv)); base::SysNSStringToUTF8(params.encoded_function_iv);
std::string decoded_function_iv;
EXPECT_TRUE(base::Base64Decode(function_iv_string, &decoded_function_iv));
std::string message_iv_string =
base::SysNSStringToUTF8(params.encoded_message_iv);
std::string decoded_message_iv;
EXPECT_TRUE(base::Base64Decode(message_iv_string, &decoded_message_iv));
// Ensure the frame ID matches. // Ensure the frame ID matches.
EXPECT_NSEQ(base::SysUTF8ToNSString(kFrameId), params.frame_id); EXPECT_NSEQ(base::SysUTF8ToNSString(kFrameId), params.frame_id);
...@@ -208,8 +234,9 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionUniqueInitializationVector) { ...@@ -208,8 +234,9 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionUniqueInitializationVector) {
RouteMessageParameters params2 = RouteMessageParameters params2 =
ParametersFromFunctionCallString(last_script2); ParametersFromFunctionCallString(last_script2);
EXPECT_NSNE(params1.encoded_function_json, params2.encoded_function_json); EXPECT_NSNE(params1.encoded_function_payload,
EXPECT_NSNE(params1.encoded_iv, params2.encoded_iv); params2.encoded_function_payload);
EXPECT_NSNE(params1.encoded_function_iv, params2.encoded_function_iv);
} }
// Tests that the WebFrame properly encodes and encrypts all parameters for // Tests that the WebFrame properly encodes and encrypts all parameters for
...@@ -238,47 +265,67 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionMessageProperlyEncoded) { ...@@ -238,47 +265,67 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionMessageProperlyEncoded) {
base::SysUTF16ToNSString(test_web_state.GetLastExecutedJavascript()); base::SysUTF16ToNSString(test_web_state.GetLastExecutedJavascript());
RouteMessageParameters params = ParametersFromFunctionCallString(last_script); RouteMessageParameters params = ParametersFromFunctionCallString(last_script);
std::string decoded_ciphertext; std::string decoded_function_ciphertext;
EXPECT_TRUE(base::Base64Decode(
base::SysNSStringToUTF8(params.encoded_function_payload),
&decoded_function_ciphertext));
std::string decoded_function_iv;
EXPECT_TRUE( EXPECT_TRUE(
base::Base64Decode(base::SysNSStringToUTF8(params.encoded_function_json), base::Base64Decode(base::SysNSStringToUTF8(params.encoded_function_iv),
&decoded_ciphertext)); &decoded_function_iv));
std::string decoded_message_ciphertext;
EXPECT_TRUE(base::Base64Decode(
base::SysNSStringToUTF8(params.encoded_message_payload),
&decoded_message_ciphertext));
std::string decoded_iv; std::string decoded_message_iv;
EXPECT_TRUE(base::Base64Decode(base::SysNSStringToUTF8(params.encoded_iv), EXPECT_TRUE(base::Base64Decode(
&decoded_iv)); base::SysNSStringToUTF8(params.encoded_message_iv), &decoded_message_iv));
// Decrypt message // Decrypt message
crypto::Aead aead(crypto::Aead::AES_256_GCM); crypto::Aead aead(crypto::Aead::AES_256_GCM);
aead.Init(&key_string); aead.Init(&key_string);
std::string plaintext; std::string function_plaintext;
EXPECT_TRUE(aead.Open(decoded_ciphertext, decoded_iv, EXPECT_TRUE(aead.Open(decoded_function_ciphertext, decoded_function_iv,
/*additional_data=*/nullptr, &plaintext)); base::NumberToString(initial_message_id),
&function_plaintext));
std::string message_plaintext;
EXPECT_TRUE(aead.Open(decoded_message_ciphertext, decoded_message_iv,
/*additional_data=*/nullptr, &message_plaintext));
base::Optional<base::Value> parsed_function_result =
base::JSONReader::Read(function_plaintext, false);
EXPECT_TRUE(parsed_function_result.has_value());
ASSERT_TRUE(parsed_function_result.value().is_dict());
base::Optional<base::Value> parsed_result = const std::string* decrypted_function_name =
base::JSONReader::Read(plaintext, false); parsed_function_result.value().FindStringKey("functionName");
EXPECT_TRUE(parsed_result.has_value()); ASSERT_TRUE(decrypted_function_name);
ASSERT_TRUE(parsed_result.value().is_dict()); EXPECT_EQ("functionName", *decrypted_function_name);
base::Value* decrypted_parameters =
parsed_function_result.value().FindKeyOfType("parameters",
base::Value::Type::LIST);
ASSERT_TRUE(decrypted_parameters);
ASSERT_EQ(function_params.size(), decrypted_parameters->GetList().size());
EXPECT_EQ(plaintext_param, decrypted_parameters->GetList()[0].GetString());
base::Optional<base::Value> parsed_message_result =
base::JSONReader::Read(message_plaintext, false);
EXPECT_TRUE(parsed_message_result.has_value());
ASSERT_TRUE(parsed_message_result.value().is_dict());
base::Optional<int> decrypted_message_id = base::Optional<int> decrypted_message_id =
parsed_result.value().FindIntKey("messageId"); parsed_message_result.value().FindIntKey("messageId");
ASSERT_TRUE(decrypted_message_id.has_value()); ASSERT_TRUE(decrypted_message_id.has_value());
EXPECT_EQ(decrypted_message_id.value(), initial_message_id); EXPECT_EQ(decrypted_message_id.value(), initial_message_id);
base::Optional<bool> decrypted_respond_with_result = base::Optional<bool> decrypted_respond_with_result =
parsed_result.value().FindBoolKey("replyWithResult"); parsed_message_result.value().FindBoolKey("replyWithResult");
ASSERT_TRUE(decrypted_respond_with_result.has_value()); ASSERT_TRUE(decrypted_respond_with_result.has_value());
EXPECT_FALSE(decrypted_respond_with_result.value()); EXPECT_FALSE(decrypted_respond_with_result.value());
const std::string* decrypted_function_name =
parsed_result.value().FindStringKey("functionName");
ASSERT_TRUE(decrypted_function_name);
EXPECT_EQ("functionName", *decrypted_function_name);
base::Value* decrypted_parameters = parsed_result.value().FindKeyOfType(
"parameters", base::Value::Type::LIST);
ASSERT_TRUE(decrypted_parameters);
ASSERT_EQ(function_params.size(), decrypted_parameters->GetList().size());
EXPECT_EQ(plaintext_param, decrypted_parameters->GetList()[0].GetString());
} }
// Tests that the WebFrame properly encodes and encrypts the respondWithResult // Tests that the WebFrame properly encodes and encrypts the respondWithResult
...@@ -310,24 +357,24 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionRespondWithResult) { ...@@ -310,24 +357,24 @@ TEST_F(WebFrameImplTest, CallJavaScriptFunctionRespondWithResult) {
base::SysUTF16ToNSString(test_web_state.GetLastExecutedJavascript()); base::SysUTF16ToNSString(test_web_state.GetLastExecutedJavascript());
RouteMessageParameters params = ParametersFromFunctionCallString(last_script); RouteMessageParameters params = ParametersFromFunctionCallString(last_script);
std::string decoded_ciphertext; std::string decoded_message_ciphertext;
EXPECT_TRUE( EXPECT_TRUE(base::Base64Decode(
base::Base64Decode(base::SysNSStringToUTF8(params.encoded_function_json), base::SysNSStringToUTF8(params.encoded_message_payload),
&decoded_ciphertext)); &decoded_message_ciphertext));
std::string decoded_iv; std::string decoded_message_iv;
EXPECT_TRUE(base::Base64Decode(base::SysNSStringToUTF8(params.encoded_iv), EXPECT_TRUE(base::Base64Decode(
&decoded_iv)); base::SysNSStringToUTF8(params.encoded_message_iv), &decoded_message_iv));
// Decrypt message // Decrypt message
crypto::Aead aead(crypto::Aead::AES_256_GCM); crypto::Aead aead(crypto::Aead::AES_256_GCM);
aead.Init(&key_string); aead.Init(&key_string);
std::string plaintext; std::string message_plaintext;
EXPECT_TRUE(aead.Open(decoded_ciphertext, decoded_iv, EXPECT_TRUE(aead.Open(decoded_message_ciphertext, decoded_message_iv,
/*additional_data=*/nullptr, &plaintext)); /*additional_data=*/nullptr, &message_plaintext));
base::Optional<base::Value> parsed_result = base::Optional<base::Value> parsed_result =
base::JSONReader::Read(plaintext, false); base::JSONReader::Read(message_plaintext, false);
EXPECT_TRUE(parsed_result.has_value()); EXPECT_TRUE(parsed_result.has_value());
ASSERT_TRUE(parsed_result.value().is_dict()); ASSERT_TRUE(parsed_result.value().is_dict());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment