Commit 0d17cd74 authored by pneubeck@chromium.org's avatar pneubeck@chromium.org

enterprise.platformKeys: Copy-on-read the 'algorithm' member of Key objects.

With this change, a Key object's algorithm member is copied on every read access. Effectively preventing it's modification as required by the WebCrypto specification.

BUG=385143
R=bartfab@chromium.org, kalman@chromium.org

Review URL: https://codereview.chromium.org/332233002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278833 0039d316-1c4b-4281-b951-d872f2087c98
parent 8d42db5b
......@@ -40,10 +40,19 @@ var KeyImpl = function(type, publicKeySpki, algorithm, usages, extractable) {
this.extractable = extractable;
};
var Key =
utils.expose('Key',
KeyImpl,
{readonly:['extractable', 'type', 'algorithm', 'usages']});
var KeyBase = function() {};
Object.defineProperty(KeyBase.prototype, 'algorithm', {
enumerable: true,
get: function() {
return utils.deepCopy(privates(this).impl.algorithm);
}
});
var Key = utils.expose(
'Key',
KeyImpl,
{superclass: KeyBase, readonly: ['extractable', 'type', 'usages']});
/**
* Returns |key|'s Subject Public Key Info. Throws an exception if |key| is not
......
......@@ -260,6 +260,49 @@ function beforeTests(callback) {
});
}
function checkAlgorithmIsCopiedOnRead(key) {
var algorithm = key.algorithm;
var originalAlgorithm = {
name: algorithm.name,
modulusLength: algorithm.modulusLength,
publicExponent: algorithm.publicExponent,
hash: {name: algorithm.hash.name}
};
var originalModulusLength = algorithm.modulusLength;
algorithm.hash.name = null;
algorithm.hash = null;
algorithm.name = null;
algorithm.modulusLength = null;
algorithm.publicExponent = null;
assertEq(originalAlgorithm, key.algorithm);
}
function checkPropertyIsReadOnly(object, key) {
var original = object[key];
try {
object[key] = {};
fail('Expected the property to be read-only and an exception to be thrown');
} catch (error) {
assertEq(original, object[key]);
}
}
function checkKeyPairCommonFormat(keyPair) {
checkPropertyIsReadOnly(keyPair, 'privateKey');
var privateKey = keyPair.privateKey;
assertEq('private', privateKey.type);
assertEq(false, privateKey.extractable);
checkPropertyIsReadOnly(privateKey, 'algorithm');
checkAlgorithmIsCopiedOnRead(privateKey);
checkPropertyIsReadOnly(keyPair, 'publicKey');
var publicKey = keyPair.publicKey;
assertEq('public', publicKey.type);
assertEq(true, publicKey.extractable);
checkPropertyIsReadOnly(publicKey, 'algorithm');
checkAlgorithmIsCopiedOnRead(publicKey);
}
function runTests(userToken) {
chrome.test.runTests([
function hasSubtleCryptoMethods() {
......@@ -308,6 +351,9 @@ function runTests(userToken) {
function(error) { fail("GenerateKey failed: " + error); })
.then(callbackPass(function(publicKeySpki) {
// Ensure that the returned key pair has the expected format.
// Some parameter independent checks:
checkKeyPairCommonFormat(cachedKeyPair);
// Checks depending on the generateKey arguments:
var privateKey = cachedKeyPair.privateKey;
assertEq(['sign'], privateKey.usages);
......
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
var createClassWrapper = requireNative('utils').createClassWrapper;
var nativeDeepCopy = requireNative('utils').deepCopy;
var schemaRegistry = requireNative('schema_registry');
var CHECK = requireNative('logging').CHECK;
var WARNING = requireNative('logging').WARNING;
......@@ -124,7 +125,16 @@ function expose(name, cls, exposed) {
return publicClass;
}
/**
* Returns a deep copy of |value|. The copy will have no references to nested
* values of |value|.
*/
function deepCopy(value) {
return nativeDeepCopy(value);
}
exports.forEach = forEach;
exports.loadTypeSchema = loadTypeSchema;
exports.lookup = lookup;
exports.expose = expose;
exports.deepCopy = deepCopy;
......@@ -7,6 +7,7 @@
#include "base/strings/stringprintf.h"
#include "extensions/renderer/script_context.h"
#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
namespace extensions {
......@@ -15,6 +16,9 @@ UtilsNativeHandler::UtilsNativeHandler(ScriptContext* context)
RouteFunction("createClassWrapper",
base::Bind(&UtilsNativeHandler::CreateClassWrapper,
base::Unretained(this)));
RouteFunction(
"deepCopy",
base::Bind(&UtilsNativeHandler::DeepCopy, base::Unretained(this)));
}
UtilsNativeHandler::~UtilsNativeHandler() {}
......@@ -81,4 +85,11 @@ void UtilsNativeHandler::CreateClassWrapper(
args.GetReturnValue().Set(result);
}
void UtilsNativeHandler::DeepCopy(
const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK_EQ(1, args.Length());
args.GetReturnValue().Set(
blink::WebSerializedScriptValue::serialize(args[0]).deserialize());
}
} // namespace extensions
......@@ -21,6 +21,11 @@ class UtilsNativeHandler : public ObjectBackedNativeHandler {
// that wraps the implementation, while hiding its members.
void CreateClassWrapper(const v8::FunctionCallbackInfo<v8::Value>& args);
// |args| consists of one argument: an arbitrary value. Returns a deep copy of
// that value. The copy will have no references to nested values of the
// argument.
void DeepCopy(const v8::FunctionCallbackInfo<v8::Value>& args);
DISALLOW_COPY_AND_ASSIGN(UtilsNativeHandler);
};
......
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