Skip to content

Commit 60147b1

Browse files
committed
Harden worker operation dispatch against unsafe dynamic method access
- operations.register/exists use Object.prototype.hasOwnProperty.call and a typeof guard so inherited Object.prototype members (toString, constructor, etc.) and the registry's own methods can no longer be resolved as crypto operations - Add operations.get() safe accessor that returns the registered function or null - worker.jsCryptoRunner validates via operations.get before invoking, removing both the throw-based DoS on unknown operationType and the unexpected-method invocation (CodeQL) - Rebuild dist bundles - Restore test iterations to 10
1 parent 34ed498 commit 60147b1

5 files changed

Lines changed: 43 additions & 15 deletions

File tree

dist/msrcrypto.js

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,24 +42,35 @@ var operations = {};
4242

4343
operations.register = function(operationType, algorithmName, functionToCall) {
4444

45-
if (!operations[operationType]) {
45+
if (!Object.prototype.hasOwnProperty.call(operations, operationType) ||
46+
typeof operations[operationType] !== "object") {
4647
operations[operationType] = {};
4748
}
4849

4950
var op = operations[operationType];
5051

51-
if (!op[algorithmName]) {
52+
if (!Object.prototype.hasOwnProperty.call(op, algorithmName)) {
5253
op[algorithmName] = functionToCall;
5354
}
5455

5556
};
5657

5758
operations.exists = function(operationType, algorithmName) {
58-
if (!operations[operationType]) {
59+
if (!Object.prototype.hasOwnProperty.call(operations, operationType) ||
60+
typeof operations[operationType] !== "object") {
5961
return false;
6062
}
6163

62-
return operations[operationType][algorithmName] ? true : false;
64+
var op = operations[operationType];
65+
66+
return Object.prototype.hasOwnProperty.call(op, algorithmName) &&
67+
typeof op[algorithmName] === "function";
68+
};
69+
70+
operations.get = function(operationType, algorithmName) {
71+
return operations.exists(operationType, algorithmName)
72+
? operations[operationType][algorithmName]
73+
: null;
6374
};
6475

6576
var scriptUrl = (function() {
@@ -849,11 +860,13 @@ var msrcryptoWorker = (function() {
849860
operationSubType = e.data.operationSubType;
850861

851862
var operation = e.data.operationType,
863+
algorithmName = e.data.algorithm.name,
852864
result,
853-
func = operations[operation][e.data.algorithm.name],
854865
p = e.data;
855866

856-
if (!operations.exists(operation, e.data.algorithm.name)) {
867+
var func = operations.get(operation, algorithmName);
868+
869+
if (!func) {
857870
throw new Error("unregistered algorithm.");
858871
}
859872

dist/msrcrypto.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/operations.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,35 @@ var operations = {};
2020

2121
operations.register = function(operationType, algorithmName, functionToCall) {
2222

23-
if (!operations[operationType]) {
23+
if (!Object.prototype.hasOwnProperty.call(operations, operationType) ||
24+
typeof operations[operationType] !== "object") {
2425
operations[operationType] = {};
2526
}
2627

2728
var op = operations[operationType];
2829

29-
if (!op[algorithmName]) {
30+
if (!Object.prototype.hasOwnProperty.call(op, algorithmName)) {
3031
op[algorithmName] = functionToCall;
3132
}
3233

3334
};
3435

3536
operations.exists = function(operationType, algorithmName) {
36-
if (!operations[operationType]) {
37+
if (!Object.prototype.hasOwnProperty.call(operations, operationType) ||
38+
typeof operations[operationType] !== "object") {
3739
return false;
3840
}
3941

40-
return operations[operationType][algorithmName] ? true : false;
42+
var op = operations[operationType];
43+
44+
return Object.prototype.hasOwnProperty.call(op, algorithmName) &&
45+
typeof op[algorithmName] === "function";
46+
};
47+
48+
// Safe accessor: returns the registered function or null.
49+
// Never resolves to an inherited Object.prototype member.
50+
operations.get = function(operationType, algorithmName) {
51+
return operations.exists(operationType, algorithmName)
52+
? operations[operationType][algorithmName]
53+
: null;
4154
};

src/worker.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ var msrcryptoWorker = (function() {
4242
operationSubType = e.data.operationSubType;
4343

4444
var operation = e.data.operationType,
45+
algorithmName = e.data.algorithm.name,
4546
result,
46-
func = operations[operation][e.data.algorithm.name],
4747
p = e.data;
4848

49-
if (!operations.exists(operation, e.data.algorithm.name)) {
49+
var func = operations.get(operation, algorithmName);
50+
51+
if (!func) {
5052
throw new Error("unregistered algorithm.");
5153
}
5254

test/Test.Shared.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ function slowTest() {
4343

4444
}
4545

46-
// Microsoft Edges does not export key_ops or alg properties
46+
// Microsoft Edge does not export key_ops or alg properties
4747
// unless keyImport included those properties
4848
// So, generateKey will be missing key_ops & alg
4949
// This will check if this is happening
@@ -59,7 +59,7 @@ function slowTest() {
5959

6060
var UseNative = false;
6161
var useWebWorkers = false;
62-
var iterations = 1;
62+
var iterations = 10;
6363
var skipSlowTests = true;
6464
var subtle = (UseNative && nativeCrypto) ? crypto.subtle : msrCrypto.subtle;
6565
var label = UseNative ? "(native)" : useWebWorkers ? "msrCrypto (workers)" : "msrCrypto";

0 commit comments

Comments
 (0)