Skip to content

Commit f2b9422

Browse files
committed
fixup! crypto: add WebCrypto CryptoJob mode
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
1 parent b93b394 commit f2b9422

4 files changed

Lines changed: 107 additions & 33 deletions

File tree

src/crypto/crypto_kem.cc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,16 +176,16 @@ MaybeLocal<Value> KEMEncapsulateTraits::EncodeOutput(
176176

177177
if (params.job_mode == kCryptoJobWebCrypto) {
178178
Local<Object> result = Object::New(env->isolate());
179-
if (result
180-
->Set(env->context(),
181-
OneByteString(env->isolate(), "sharedKey"),
182-
shared_key_obj.As<ArrayBufferView>()->Buffer())
183-
.IsNothing() ||
184-
result
185-
->Set(env->context(),
186-
OneByteString(env->isolate(), "ciphertext"),
187-
ciphertext_obj.As<ArrayBufferView>()->Buffer())
188-
.IsNothing()) {
179+
if (!result
180+
->DefineOwnProperty(env->context(),
181+
OneByteString(env->isolate(), "sharedKey"),
182+
shared_key_obj.As<ArrayBufferView>()->Buffer())
183+
.FromMaybe(false) ||
184+
!result
185+
->DefineOwnProperty(env->context(),
186+
OneByteString(env->isolate(), "ciphertext"),
187+
ciphertext_obj.As<ArrayBufferView>()->Buffer())
188+
.FromMaybe(false)) {
189189
return MaybeLocal<Value>();
190190
}
191191
return result;

src/crypto/crypto_keygen.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,14 @@ class KeyGenJob final : public CryptoJob<KeyGenTraits> {
184184
}
185185

186186
v8::Local<v8::Object> ret = v8::Object::New(isolate);
187-
if (ret->Set(env->context(),
188-
OneByteString(isolate, "publicKey"),
189-
public_key)
190-
.IsNothing() ||
191-
ret->Set(env->context(),
192-
OneByteString(isolate, "privateKey"),
193-
private_key)
194-
.IsNothing()) {
187+
if (!ret->DefineOwnProperty(env->context(),
188+
OneByteString(isolate, "publicKey"),
189+
public_key)
190+
.FromMaybe(false) ||
191+
!ret->DefineOwnProperty(env->context(),
192+
OneByteString(isolate, "privateKey"),
193+
private_key)
194+
.FromMaybe(false)) {
195195
return {};
196196
}
197197
return ret;

src/crypto/crypto_util.cc

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -735,13 +735,15 @@ MaybeLocal<Value> CreateWebCryptoJobError(Environment* env,
735735
CHECK(domexception_ctor->IsFunction());
736736

737737
Local<Object> options = Object::New(isolate);
738-
if (options
739-
->Set(context,
740-
FIXED_ONE_BYTE_STRING(isolate, "name"),
741-
FIXED_ONE_BYTE_STRING(isolate, "OperationError"))
742-
.IsNothing() ||
743-
options->Set(context, FIXED_ONE_BYTE_STRING(isolate, "cause"), cause)
744-
.IsNothing()) {
738+
if (!options
739+
->DefineOwnProperty(context,
740+
FIXED_ONE_BYTE_STRING(isolate, "name"),
741+
FIXED_ONE_BYTE_STRING(isolate, "OperationError"))
742+
.FromMaybe(false) ||
743+
!options
744+
->DefineOwnProperty(
745+
context, FIXED_ONE_BYTE_STRING(isolate, "cause"), cause)
746+
.FromMaybe(false)) {
745747
return {};
746748
}
747749

test/parallel/test-webcrypto-crypto-job-mode.js

Lines changed: 80 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ if (!common.hasCrypto)
77
common.skip('missing crypto');
88

99
const assert = require('assert');
10+
const { hasOpenSSL } = require('../common/crypto');
1011
const { types: { isCryptoKey } } = require('util');
1112
const { internalBinding } = require('internal/test/binding');
1213
const {
@@ -31,6 +32,34 @@ const {
3132

3233
const { subtle } = globalThis.crypto;
3334

35+
// Defines Object.prototype setters that fail the test if native result object
36+
// creation uses [[Set]] instead of creating own data properties.
37+
async function withObjectPrototypeSetters(names, fn) {
38+
const descriptors = new Map();
39+
for (const name of names) {
40+
descriptors.set(name, Object.getOwnPropertyDescriptor(Object.prototype, name));
41+
Object.defineProperty(Object.prototype, name, {
42+
__proto__: null,
43+
configurable: true,
44+
get: common.mustNotCall(`Object.prototype.${name} getter`),
45+
set: common.mustNotCall(`Object.prototype.${name} setter`),
46+
});
47+
}
48+
49+
try {
50+
return await fn();
51+
} finally {
52+
for (const name of names) {
53+
const descriptor = descriptors.get(name);
54+
if (descriptor === undefined) {
55+
delete Object.prototype[name];
56+
} else {
57+
Object.defineProperty(Object.prototype, name, descriptor);
58+
}
59+
}
60+
}
61+
}
62+
3463
(async function() {
3564
{
3665
const promise = new HashJob(
@@ -67,14 +96,16 @@ const { subtle } = globalThis.crypto;
6796
}
6897

6998
{
70-
const pair = await new EcKeyPairGenJob(
71-
kCryptoJobWebCrypto,
72-
'P-256',
73-
undefined,
74-
{ name: 'ECDSA', namedCurve: 'P-256' },
75-
getUsagesMask(new Set(['verify'])),
76-
getUsagesMask(new Set(['sign'])),
77-
true).run();
99+
const pair = await withObjectPrototypeSetters(
100+
['publicKey', 'privateKey'],
101+
() => new EcKeyPairGenJob(
102+
kCryptoJobWebCrypto,
103+
'P-256',
104+
undefined,
105+
{ name: 'ECDSA', namedCurve: 'P-256' },
106+
getUsagesMask(new Set(['verify'])),
107+
getUsagesMask(new Set(['sign'])),
108+
true).run());
78109

79110
assert.strictEqual(Object.getPrototypeOf(pair), Object.prototype);
80111
assert(isCryptoKey(pair.publicKey));
@@ -120,6 +151,33 @@ const { subtle } = globalThis.crypto;
120151
});
121152
}
122153

154+
{
155+
const key = await subtle.generateKey(
156+
{ name: 'AES-CBC', length: 128 },
157+
false,
158+
['encrypt', 'decrypt']);
159+
const iv = crypto.getRandomValues(new Uint8Array(16));
160+
const ciphertext = new Uint8Array(await subtle.encrypt(
161+
{ name: 'AES-CBC', iv },
162+
key,
163+
Buffer.alloc(16)));
164+
ciphertext[ciphertext.length - 1] ^= 0xff;
165+
166+
await assert.rejects(
167+
withObjectPrototypeSetters(['cause'], () =>
168+
subtle.decrypt({ name: 'AES-CBC', iv }, key, ciphertext)),
169+
(err) => {
170+
assert.strictEqual(err.name, 'OperationError');
171+
assert.strictEqual(
172+
err.message,
173+
'The operation failed for an operation-specific reason');
174+
assert(err.cause);
175+
assert.strictEqual(typeof err.cause.message, 'string');
176+
assert.notStrictEqual(err.cause.message, '');
177+
return true;
178+
});
179+
}
180+
123181
{
124182
const key = await subtle.generateKey(
125183
{ name: 'HMAC', hash: 'SHA-256' },
@@ -151,4 +209,18 @@ const { subtle } = globalThis.crypto;
151209
delete CryptoKey.prototype.then;
152210
}
153211
}
212+
213+
if (hasOpenSSL(3, 5)) {
214+
const pair = await subtle.generateKey(
215+
{ name: 'ML-KEM-768' },
216+
true,
217+
['encapsulateBits', 'decapsulateBits']);
218+
const result = await withObjectPrototypeSetters(
219+
['sharedKey', 'ciphertext'],
220+
() => subtle.encapsulateBits({ name: 'ML-KEM-768' }, pair.publicKey));
221+
222+
assert.strictEqual(Object.getPrototypeOf(result), Object.prototype);
223+
assert(result.sharedKey instanceof ArrayBuffer);
224+
assert(result.ciphertext instanceof ArrayBuffer);
225+
}
154226
})().then(common.mustCall());

0 commit comments

Comments
 (0)