Skip to content

Commit ea8d83b

Browse files
XadillaXtargos
authored andcommitted
src,crypto: fix 0-length output crash in webcrypto
Fixes: #38883 PR-URL: #38913 Refs: #38883 Reviewed-By: Tobias Nießen <[email protected]>
1 parent 90ec766 commit ea8d83b

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

Diff for: src/crypto/crypto_aes.cc

+11-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,17 @@ WebCryptoCipherStatus AES_Cipher(
130130
ByteSource buf = ByteSource::Allocated(data, buf_len);
131131
unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
132132

133-
if (!EVP_CipherUpdate(
133+
// In some outdated version of OpenSSL (e.g.
134+
// ubi81_sharedlibs_openssl111fips_x64) may be used in sharedlib mode, the
135+
// logic will be failed when input size is zero. The newly OpenSSL has fixed
136+
// it up. But we still have to regard zero as special in Node.js code to
137+
// prevent old OpenSSL failure.
138+
//
139+
// Refs: https://github.com/openssl/openssl/commit/420cb707b880e4fb649094241371701013eeb15f
140+
// Refs: https://github.com/nodejs/node/pull/38913#issuecomment-866505244
141+
if (in.size() == 0) {
142+
out_len = 0;
143+
} else if (!EVP_CipherUpdate(
134144
ctx.get(),
135145
ptr,
136146
&out_len,

Diff for: src/crypto/crypto_cipher.h

+5-4
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,17 @@ class CipherJob final : public CryptoJob<CipherTraits> {
249249
v8::Local<v8::Value>* result) override {
250250
Environment* env = AsyncWrap::env();
251251
CryptoErrorStore* errors = CryptoJob<CipherTraits>::errors();
252-
if (out_.size() > 0) {
252+
253+
if (errors->Empty())
254+
errors->Capture();
255+
256+
if (out_.size() > 0 || errors->Empty()) {
253257
CHECK(errors->Empty());
254258
*err = v8::Undefined(env->isolate());
255259
*result = out_.ToArrayBuffer(env);
256260
return v8::Just(!result->IsEmpty());
257261
}
258262

259-
if (errors->Empty())
260-
errors->Capture();
261-
CHECK(!errors->Empty());
262263
*result = v8::Undefined(env->isolate());
263264
return v8::Just(errors->ToException(env).ToLocal(err));
264265
}

Diff for: test/parallel/test-crypto-subtle-zero-length.js

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
5+
if (!common.hasCrypto)
6+
common.skip('missing crypto');
7+
8+
const assert = require('assert');
9+
const crypto = require('crypto').webcrypto;
10+
11+
(async () => {
12+
const k = await crypto.subtle.importKey(
13+
'raw',
14+
new Uint8Array(32),
15+
{ name: 'AES-GCM' },
16+
false,
17+
[ 'encrypt', 'decrypt' ]);
18+
assert(k instanceof crypto.CryptoKey);
19+
20+
const e = await crypto.subtle.encrypt({
21+
name: 'AES-GCM',
22+
iv: new Uint8Array(12),
23+
}, k, new Uint8Array(0));
24+
assert(e instanceof ArrayBuffer);
25+
assert.deepStrictEqual(
26+
Buffer.from(e),
27+
Buffer.from([
28+
0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9,
29+
0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b ]));
30+
31+
const v = await crypto.subtle.decrypt({
32+
name: 'AES-GCM',
33+
iv: new Uint8Array(12),
34+
}, k, e);
35+
assert(v instanceof ArrayBuffer);
36+
assert.strictEqual(v.byteLength, 0);
37+
})().then(common.mustCall()).catch((e) => {
38+
assert.ifError(e);
39+
});

0 commit comments

Comments
 (0)