Skip to content

Commit

Permalink
fix(ext/crypto): throw on key & op algo mismatch (denoland#12838)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucacasonato committed Dec 3, 2021
1 parent a54f9c4 commit 1ce63f1
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 188 deletions.
204 changes: 120 additions & 84 deletions ext/crypto/00_crypto.js
Expand Up @@ -472,88 +472,23 @@
// 3.
const normalizedAlgorithm = normalizeAlgorithm(algorithm, "encrypt");

const handle = key[_handle];
const keyData = WeakMapPrototypeGet(KEY_STORE, handle);

switch (normalizedAlgorithm.name) {
case "RSA-OAEP": {
// 1.
if (key[_type] !== "public") {
throw new DOMException(
"Key type not supported",
"InvalidAccessError",
);
}

// 2.
if (normalizedAlgorithm.label) {
if (ArrayBufferIsView(normalizedAlgorithm.label)) {
normalizedAlgorithm.label = new Uint8Array(
normalizedAlgorithm.label.buffer,
normalizedAlgorithm.label.byteOffset,
normalizedAlgorithm.label.byteLength,
);
} else {
normalizedAlgorithm.label = new Uint8Array(
normalizedAlgorithm.label,
);
}
normalizedAlgorithm.label = TypedArrayPrototypeSlice(
normalizedAlgorithm.label,
);
} else {
normalizedAlgorithm.label = new Uint8Array();
}

// 3-5.
const hashAlgorithm = key[_algorithm].hash.name;
const cipherText = await core.opAsync("op_crypto_encrypt_key", {
key: keyData,
algorithm: "RSA-OAEP",
hash: hashAlgorithm,
}, data);

// 6.
return cipherText.buffer;
}
case "AES-CBC": {
if (ArrayBufferIsView(normalizedAlgorithm.iv)) {
normalizedAlgorithm.iv = new Uint8Array(
normalizedAlgorithm.iv.buffer,
normalizedAlgorithm.iv.byteOffset,
normalizedAlgorithm.iv.byteLength,
);
} else {
normalizedAlgorithm.iv = new Uint8Array(
normalizedAlgorithm.iv,
);
}
normalizedAlgorithm.iv = TypedArrayPrototypeSlice(
normalizedAlgorithm.iv,
);

// 1.
if (normalizedAlgorithm.iv.byteLength !== 16) {
throw new DOMException(
"Initialization vector must be 16 bytes",
"OperationError",
);
}

// 2.
const cipherText = await core.opAsync("op_crypto_encrypt_key", {
key: keyData,
algorithm: "AES-CBC",
length: key[_algorithm].length,
iv: normalizedAlgorithm.iv,
}, data);
// 8.
if (normalizedAlgorithm.name !== key[_algorithm].name) {
throw new DOMException(
"Encryption algorithm doesn't match key algorithm.",
"InvalidAccessError",
);
}

// 4.
return cipherText.buffer;
}
default:
throw new DOMException("Not implemented", "NotSupportedError");
// 9.
if (!ArrayPrototypeIncludes(key[_usages], "encrypt")) {
throw new DOMException(
"Key does not support the 'encrypt' operation.",
"InvalidAccessError",
);
}

return await encrypt(normalizedAlgorithm, key, data);
}

/**
Expand Down Expand Up @@ -590,6 +525,22 @@
// 3.
const normalizedAlgorithm = normalizeAlgorithm(algorithm, "decrypt");

// 8.
if (normalizedAlgorithm.name !== key[_algorithm].name) {
throw new DOMException(
"Decryption algorithm doesn't match key algorithm.",
"OperationError",
);
}

// 9.
if (!ArrayPrototypeIncludes(key[_usages], "decrypt")) {
throw new DOMException(
"Key does not support the 'decrypt' operation.",
"InvalidAccessError",
);
}

const handle = key[_handle];
const keyData = WeakMapPrototypeGet(KEY_STORE, handle);

Expand Down Expand Up @@ -1415,7 +1366,7 @@

// 4-7.
const algorithm = {
name: "AES-CBC",
name: "AES-CTR",
length: keyData.byteLength * 8,
};

Expand Down Expand Up @@ -1471,7 +1422,7 @@

// 4-7.
const algorithm = {
name: "AES-CTR",
name: "AES-CBC",
length: keyData.byteLength * 8,
};

Expand Down Expand Up @@ -2238,7 +2189,7 @@
let bytes;
// 13.
if (format !== "jwk") {
bytes = exportedKey;
bytes = new Uint8Array(exportedKey);
} else {
// TODO(@littledivy): Implement JWK.
throw new DOMException(
Expand All @@ -2259,7 +2210,7 @@
} else if (
supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
) {
return this.encrypt(normalizedAlgorithm, wrappingKey, bytes);
return await encrypt(normalizedAlgorithm, wrappingKey, bytes);
} else {
throw new DOMException(
"Algorithm not supported",
Expand Down Expand Up @@ -2819,6 +2770,91 @@
}
}

async function encrypt(normalizedAlgorithm, key, data) {
const handle = key[_handle];
const keyData = WeakMapPrototypeGet(KEY_STORE, handle);

switch (normalizedAlgorithm.name) {
case "RSA-OAEP": {
// 1.
if (key[_type] !== "public") {
throw new DOMException(
"Key type not supported",
"InvalidAccessError",
);
}

// 2.
if (normalizedAlgorithm.label) {
if (ArrayBufferIsView(normalizedAlgorithm.label)) {
normalizedAlgorithm.label = new Uint8Array(
normalizedAlgorithm.label.buffer,
normalizedAlgorithm.label.byteOffset,
normalizedAlgorithm.label.byteLength,
);
} else {
normalizedAlgorithm.label = new Uint8Array(
normalizedAlgorithm.label,
);
}
normalizedAlgorithm.label = TypedArrayPrototypeSlice(
normalizedAlgorithm.label,
);
} else {
normalizedAlgorithm.label = new Uint8Array();
}

// 3-5.
const hashAlgorithm = key[_algorithm].hash.name;
const cipherText = await core.opAsync("op_crypto_encrypt_key", {
key: keyData,
algorithm: "RSA-OAEP",
hash: hashAlgorithm,
}, data);

// 6.
return cipherText.buffer;
}
case "AES-CBC": {
if (ArrayBufferIsView(normalizedAlgorithm.iv)) {
normalizedAlgorithm.iv = new Uint8Array(
normalizedAlgorithm.iv.buffer,
normalizedAlgorithm.iv.byteOffset,
normalizedAlgorithm.iv.byteLength,
);
} else {
normalizedAlgorithm.iv = new Uint8Array(
normalizedAlgorithm.iv,
);
}
normalizedAlgorithm.iv = TypedArrayPrototypeSlice(
normalizedAlgorithm.iv,
);

// 1.
if (normalizedAlgorithm.iv.byteLength !== 16) {
throw new DOMException(
"Initialization vector must be 16 bytes",
"OperationError",
);
}

// 2.
const cipherText = await core.opAsync("op_crypto_encrypt_key", {
key: keyData,
algorithm: "AES-CBC",
length: key[_algorithm].length,
iv: normalizedAlgorithm.iv,
}, data);

// 4.
return cipherText.buffer;
}
default:
throw new DOMException("Not implemented", "NotSupportedError");
}
}

webidl.configurePrototype(SubtleCrypto);
const subtle = webidl.createBranded(SubtleCrypto);

Expand Down

0 comments on commit 1ce63f1

Please sign in to comment.