mirror of
https://github.com/denoland/deno.git
synced 2024-12-24 08:09:08 -05:00
feat(node/crypto): Diffie Hellman Support (#18943)
Support crypto.DiffieHellman class in ext/node/crypto
This commit is contained in:
parent
bfe93c6e81
commit
3356173d00
7 changed files with 372 additions and 27 deletions
|
@ -45,6 +45,7 @@
|
|||
"test-child-process-stdout-flush-exit.js",
|
||||
"test-child-process-stdout-flush.js",
|
||||
"test-console-instance.js",
|
||||
"test-crypto-dh.js",
|
||||
"test-crypto-hkdf.js",
|
||||
"test-crypto-hmac.js",
|
||||
"test-crypto-prime.js",
|
||||
|
@ -239,6 +240,7 @@
|
|||
"test-console-sync-write-error.js",
|
||||
"test-console-table.js",
|
||||
"test-console-tty-colors.js",
|
||||
"test-crypto-dh.js",
|
||||
"test-crypto-hkdf.js",
|
||||
"test-crypto-hmac.js",
|
||||
"test-crypto-prime.js",
|
||||
|
|
214
cli/tests/node_compat/test/parallel/test-crypto-dh.js
Normal file
214
cli/tests/node_compat/test/parallel/test-crypto-dh.js
Normal file
|
@ -0,0 +1,214 @@
|
|||
// deno-fmt-ignore-file
|
||||
// deno-lint-ignore-file
|
||||
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
// Taken from Node 18.12.1
|
||||
// This file is automatically generated by "node/_tools/setup.ts". Do not modify this file manually
|
||||
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
if (!common.hasCrypto)
|
||||
common.skip('missing crypto');
|
||||
|
||||
const assert = require('assert');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const size = common.hasFipsCrypto || common.hasOpenSSL3 ? 1024 : 256;
|
||||
const dh1 = crypto.createDiffieHellman(size);
|
||||
const p1 = dh1.getPrime('buffer');
|
||||
const dh2 = crypto.createDiffieHellman(p1, 'buffer');
|
||||
const key1 = dh1.generateKeys();
|
||||
const key2 = dh2.generateKeys('hex');
|
||||
const secret1 = dh1.computeSecret(key2, 'hex', 'base64');
|
||||
const secret2 = dh2.computeSecret(key1, 'latin1', 'buffer');
|
||||
|
||||
// Test Diffie-Hellman with two parties sharing a secret,
|
||||
// using various encodings as we go along
|
||||
assert.strictEqual(secret2.toString('base64'), secret1);
|
||||
assert.strictEqual(dh1.verifyError, 0);
|
||||
assert.strictEqual(dh2.verifyError, 0);
|
||||
|
||||
// https://github.com/nodejs/node/issues/32738
|
||||
// XXX(bnoordhuis) validateInt32() throwing ERR_OUT_OF_RANGE and RangeError
|
||||
// instead of ERR_INVALID_ARG_TYPE and TypeError is questionable, IMO.
|
||||
assert.throws(() => crypto.createDiffieHellman(13.37), {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
name: 'RangeError',
|
||||
message: 'The value of "sizeOrKey" is out of range. ' +
|
||||
'It must be an integer. Received 13.37',
|
||||
});
|
||||
|
||||
assert.throws(() => crypto.createDiffieHellman('abcdef', 13.37), {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
name: 'RangeError',
|
||||
message: 'The value of "generator" is out of range. ' +
|
||||
'It must be an integer. Received 13.37',
|
||||
});
|
||||
|
||||
for (const bits of [-1, 0, 1]) {
|
||||
if (common.hasOpenSSL3) {
|
||||
assert.throws(() => crypto.createDiffieHellman(bits), {
|
||||
code: 'ERR_OSSL_DH_MODULUS_TOO_SMALL',
|
||||
name: 'Error',
|
||||
message: /modulus too small/,
|
||||
});
|
||||
} else {
|
||||
assert.throws(() => crypto.createDiffieHellman(bits), {
|
||||
code: 'ERR_OSSL_BN_BITS_TOO_SMALL',
|
||||
name: 'Error',
|
||||
message: /bits too small/,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Through a fluke of history, g=0 defaults to DH_GENERATOR (2).
|
||||
{
|
||||
const g = 0;
|
||||
crypto.createDiffieHellman('abcdef', g);
|
||||
crypto.createDiffieHellman('abcdef', 'hex', g);
|
||||
}
|
||||
|
||||
for (const g of [-1, 1]) {
|
||||
const ex = {
|
||||
code: 'ERR_OSSL_DH_BAD_GENERATOR',
|
||||
name: 'Error',
|
||||
message: /bad generator/,
|
||||
};
|
||||
assert.throws(() => crypto.createDiffieHellman('abcdef', g), ex);
|
||||
assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex);
|
||||
}
|
||||
|
||||
crypto.createDiffieHellman('abcdef', Buffer.from([2])); // OK
|
||||
|
||||
for (const g of [Buffer.from([]),
|
||||
Buffer.from([0]),
|
||||
Buffer.from([1])]) {
|
||||
const ex = {
|
||||
code: 'ERR_OSSL_DH_BAD_GENERATOR',
|
||||
name: 'Error',
|
||||
message: /bad generator/,
|
||||
};
|
||||
assert.throws(() => crypto.createDiffieHellman('abcdef', g), ex);
|
||||
assert.throws(() => crypto.createDiffieHellman('abcdef', 'hex', g), ex);
|
||||
}
|
||||
|
||||
[
|
||||
[0x1, 0x2],
|
||||
() => { },
|
||||
/abc/,
|
||||
{},
|
||||
].forEach((input) => {
|
||||
assert.throws(
|
||||
() => crypto.createDiffieHellman(input),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Create "another dh1" using generated keys from dh1,
|
||||
// and compute secret again
|
||||
const dh3 = crypto.createDiffieHellman(p1, 'buffer');
|
||||
const privkey1 = dh1.getPrivateKey();
|
||||
dh3.setPublicKey(key1);
|
||||
dh3.setPrivateKey(privkey1);
|
||||
|
||||
assert.deepStrictEqual(dh1.getPrime(), dh3.getPrime());
|
||||
assert.deepStrictEqual(dh1.getGenerator(), dh3.getGenerator());
|
||||
assert.deepStrictEqual(dh1.getPublicKey(), dh3.getPublicKey());
|
||||
assert.deepStrictEqual(dh1.getPrivateKey(), dh3.getPrivateKey());
|
||||
assert.strictEqual(dh3.verifyError, 0);
|
||||
|
||||
const secret3 = dh3.computeSecret(key2, 'hex', 'base64');
|
||||
|
||||
assert.strictEqual(secret1, secret3);
|
||||
|
||||
// computeSecret works without a public key set at all.
|
||||
const dh4 = crypto.createDiffieHellman(p1, 'buffer');
|
||||
dh4.setPrivateKey(privkey1);
|
||||
|
||||
assert.deepStrictEqual(dh1.getPrime(), dh4.getPrime());
|
||||
assert.deepStrictEqual(dh1.getGenerator(), dh4.getGenerator());
|
||||
assert.deepStrictEqual(dh1.getPrivateKey(), dh4.getPrivateKey());
|
||||
assert.strictEqual(dh4.verifyError, 0);
|
||||
|
||||
const secret4 = dh4.computeSecret(key2, 'hex', 'base64');
|
||||
|
||||
assert.strictEqual(secret1, secret4);
|
||||
|
||||
|
||||
if (false) {
|
||||
let wrongBlockLength;
|
||||
if (common.hasOpenSSL3) {
|
||||
wrongBlockLength = {
|
||||
message: 'error:1C80006B:Provider routines::wrong final block length',
|
||||
code: 'ERR_OSSL_WRONG_FINAL_BLOCK_LENGTH',
|
||||
library: 'Provider routines',
|
||||
reason: 'wrong final block length'
|
||||
};
|
||||
} else {
|
||||
wrongBlockLength = {
|
||||
message: 'error:0606506D:digital envelope' +
|
||||
' routines:EVP_DecryptFinal_ex:wrong final block length',
|
||||
code: 'ERR_OSSL_EVP_WRONG_FINAL_BLOCK_LENGTH',
|
||||
library: 'digital envelope routines',
|
||||
reason: 'wrong final block length'
|
||||
};
|
||||
}
|
||||
|
||||
// Run this one twice to make sure that the dh3 clears its error properly
|
||||
{
|
||||
const c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
|
||||
assert.throws(() => {
|
||||
c.final('utf8');
|
||||
}, wrongBlockLength);
|
||||
}
|
||||
|
||||
{
|
||||
const c = crypto.createDecipheriv('aes-128-ecb', crypto.randomBytes(16), '');
|
||||
assert.throws(() => {
|
||||
c.final('utf8');
|
||||
}, wrongBlockLength);
|
||||
}
|
||||
|
||||
assert.throws(() => {
|
||||
dh3.computeSecret('');
|
||||
}, { message: common.hasOpenSSL3 ?
|
||||
'error:02800080:Diffie-Hellman routines::invalid secret' :
|
||||
'Supplied key is too small' });
|
||||
|
||||
// Invalid test: curve argument is undefined
|
||||
assert.throws(
|
||||
() => crypto.createECDH(),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: 'The "curve" argument must be of type string. ' +
|
||||
'Received undefined'
|
||||
});
|
||||
|
||||
assert.throws(
|
||||
function() {
|
||||
crypto.getDiffieHellman('unknown-group');
|
||||
},
|
||||
{
|
||||
name: 'Error',
|
||||
code: 'ERR_CRYPTO_UNKNOWN_DH_GROUP',
|
||||
message: 'Unknown DH group'
|
||||
},
|
||||
'crypto.getDiffieHellman(\'unknown-group\') ' +
|
||||
'failed to throw the expected error.'
|
||||
);
|
||||
}
|
||||
|
||||
assert.throws(
|
||||
() => crypto.createDiffieHellman('', true),
|
||||
{
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
}
|
||||
);
|
||||
[true, Symbol(), {}, () => {}, []].forEach((generator) => assert.throws(
|
||||
() => crypto.createDiffieHellman('', 'base64', generator),
|
||||
{ code: 'ERR_INVALID_ARG_TYPE' }
|
||||
));
|
|
@ -170,6 +170,8 @@ deno_core::extension!(deno_node,
|
|||
ops::crypto::op_node_dh_generate_group,
|
||||
ops::crypto::op_node_dh_generate_group_async,
|
||||
ops::crypto::op_node_dh_generate,
|
||||
ops::crypto::op_node_dh_generate2,
|
||||
ops::crypto::op_node_dh_compute_secret,
|
||||
ops::crypto::op_node_dh_generate_async,
|
||||
ops::crypto::op_node_verify,
|
||||
ops::crypto::op_node_random_int,
|
||||
|
|
|
@ -63,7 +63,7 @@ impl DiffieHellman {
|
|||
}
|
||||
|
||||
pub fn new(prime: Prime, generator: usize) -> Self {
|
||||
let private_key = PrivateKey::new(32);
|
||||
let private_key = PrivateKey::new(prime.bits());
|
||||
|
||||
let generator = BigUint::from_usize(generator).unwrap();
|
||||
let public_key = private_key.compute_public_key(&generator, &prime);
|
||||
|
|
|
@ -11,6 +11,7 @@ use deno_core::StringOrBuffer;
|
|||
use deno_core::ZeroCopyBuf;
|
||||
use hkdf::Hkdf;
|
||||
use num_bigint::BigInt;
|
||||
use num_bigint_dig::BigUint;
|
||||
use num_traits::FromPrimitive;
|
||||
use rand::distributions::Distribution;
|
||||
use rand::distributions::Uniform;
|
||||
|
@ -788,6 +789,30 @@ pub fn op_node_dh_generate(
|
|||
dh_generate(prime, prime_len, generator)
|
||||
}
|
||||
|
||||
// TODO(lev): This duplication should be avoided.
|
||||
#[op]
|
||||
pub fn op_node_dh_generate2(
|
||||
prime: ZeroCopyBuf,
|
||||
prime_len: usize,
|
||||
generator: usize,
|
||||
) -> Result<(ZeroCopyBuf, ZeroCopyBuf), AnyError> {
|
||||
dh_generate(Some(prime).as_deref(), prime_len, generator)
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub fn op_node_dh_compute_secret(
|
||||
prime: ZeroCopyBuf,
|
||||
private_key: ZeroCopyBuf,
|
||||
their_public_key: ZeroCopyBuf,
|
||||
) -> Result<ZeroCopyBuf, AnyError> {
|
||||
let pubkey: BigUint = BigUint::from_bytes_be(their_public_key.as_ref());
|
||||
let privkey: BigUint = BigUint::from_bytes_be(private_key.as_ref());
|
||||
let primei: BigUint = BigUint::from_bytes_be(prime.as_ref());
|
||||
let shared_secret: BigUint = pubkey.modpow(&privkey, &primei);
|
||||
|
||||
Ok(shared_secret.to_bytes_be().into())
|
||||
}
|
||||
|
||||
#[op]
|
||||
pub async fn op_node_dh_generate_async(
|
||||
prime: Option<ZeroCopyBuf>,
|
||||
|
|
|
@ -6,7 +6,10 @@ import {
|
|||
isAnyArrayBuffer,
|
||||
isArrayBufferView,
|
||||
} from "ext:deno_node/internal/util/types.ts";
|
||||
import { ERR_INVALID_ARG_TYPE } from "ext:deno_node/internal/errors.ts";
|
||||
import {
|
||||
ERR_INVALID_ARG_TYPE,
|
||||
NodeError,
|
||||
} from "ext:deno_node/internal/errors.ts";
|
||||
import {
|
||||
validateInt32,
|
||||
validateString,
|
||||
|
@ -32,9 +35,14 @@ const DH_GENERATOR = 2;
|
|||
|
||||
export class DiffieHellman {
|
||||
verifyError!: number;
|
||||
#prime: Buffer;
|
||||
#primeLength: number;
|
||||
#generator: Buffer;
|
||||
#privateKey: Buffer;
|
||||
#publicKey: Buffer;
|
||||
|
||||
constructor(
|
||||
sizeOrKey: unknown,
|
||||
sizeOrKey: number | string | ArrayBufferView,
|
||||
keyEncoding?: unknown,
|
||||
generator?: unknown,
|
||||
genEncoding?: unknown,
|
||||
|
@ -71,24 +79,68 @@ export class DiffieHellman {
|
|||
genEncoding = genEncoding || encoding;
|
||||
|
||||
if (typeof sizeOrKey !== "number") {
|
||||
sizeOrKey = toBuf(sizeOrKey as string, keyEncoding as string);
|
||||
this.#prime = toBuf(sizeOrKey as string, keyEncoding as string);
|
||||
} else {
|
||||
// The supplied parameter is our primeLength, generate a suitable prime.
|
||||
this.#primeLength = sizeOrKey as number;
|
||||
if (this.#primeLength < 2) {
|
||||
throw new NodeError("ERR_OSSL_BN_BITS_TOO_SMALL", "bits too small");
|
||||
}
|
||||
|
||||
this.#prime = Buffer.from(
|
||||
ops.op_node_gen_prime(this.#primeLength).buffer,
|
||||
);
|
||||
}
|
||||
|
||||
if (!generator) {
|
||||
generator = DH_GENERATOR;
|
||||
// While the commonly used cyclic group generators for DH are 2 and 5, we
|
||||
// need this a buffer, because, well.. Node.
|
||||
this.#generator = Buffer.alloc(4);
|
||||
this.#generator.writeUint32BE(DH_GENERATOR);
|
||||
} else if (typeof generator === "number") {
|
||||
validateInt32(generator, "generator");
|
||||
this.#generator = Buffer.alloc(4);
|
||||
if (generator <= 0 || generator >= 0x7fffffff) {
|
||||
throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
|
||||
}
|
||||
this.#generator.writeUint32BE(generator);
|
||||
} else if (typeof generator === "string") {
|
||||
generator = toBuf(generator, genEncoding as string);
|
||||
this.#generator = generator;
|
||||
} else if (!isArrayBufferView(generator) && !isAnyArrayBuffer(generator)) {
|
||||
throw new ERR_INVALID_ARG_TYPE(
|
||||
"generator",
|
||||
["number", "string", "ArrayBuffer", "Buffer", "TypedArray", "DataView"],
|
||||
generator,
|
||||
);
|
||||
} else {
|
||||
this.#generator = Buffer.from(generator);
|
||||
}
|
||||
|
||||
notImplemented("crypto.DiffieHellman");
|
||||
this.#checkGenerator();
|
||||
|
||||
// TODO(lev): actually implement this value
|
||||
this.verifyError = 0;
|
||||
}
|
||||
|
||||
#checkGenerator(): number {
|
||||
let generator: number;
|
||||
|
||||
if (this.#generator.length == 0) {
|
||||
throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
|
||||
} else if (this.#generator.length == 1) {
|
||||
generator = this.#generator.readUint8();
|
||||
} else if (this.#generator.length == 2) {
|
||||
generator = this.#generator.readUint16BE();
|
||||
} else {
|
||||
generator = this.#generator.readUint32BE();
|
||||
}
|
||||
|
||||
if (generator != 2 && generator != 5) {
|
||||
throw new NodeError("ERR_OSSL_DH_BAD_GENERATOR", "bad generator");
|
||||
}
|
||||
|
||||
return generator;
|
||||
}
|
||||
|
||||
computeSecret(otherPublicKey: ArrayBufferView): Buffer;
|
||||
|
@ -106,59 +158,110 @@ export class DiffieHellman {
|
|||
outputEncoding: BinaryToTextEncoding,
|
||||
): string;
|
||||
computeSecret(
|
||||
_otherPublicKey: ArrayBufferView | string,
|
||||
_inputEncoding?: BinaryToTextEncoding,
|
||||
_outputEncoding?: BinaryToTextEncoding,
|
||||
otherPublicKey: ArrayBufferView | string,
|
||||
inputEncoding?: BinaryToTextEncoding,
|
||||
outputEncoding?: BinaryToTextEncoding,
|
||||
): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.computeSecret");
|
||||
let buf;
|
||||
if (inputEncoding != undefined && inputEncoding != "buffer") {
|
||||
buf = Buffer.from(otherPublicKey.buffer, inputEncoding);
|
||||
} else {
|
||||
buf = Buffer.from(otherPublicKey.buffer);
|
||||
}
|
||||
|
||||
const sharedSecret = ops.op_node_dh_compute_secret(
|
||||
this.#prime,
|
||||
this.#privateKey,
|
||||
buf,
|
||||
);
|
||||
|
||||
if (outputEncoding == undefined || outputEncoding == "buffer") {
|
||||
return Buffer.from(sharedSecret.buffer);
|
||||
}
|
||||
|
||||
return Buffer.from(sharedSecret.buffer).toString(outputEncoding);
|
||||
}
|
||||
|
||||
generateKeys(): Buffer;
|
||||
generateKeys(encoding: BinaryToTextEncoding): string;
|
||||
generateKeys(_encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.generateKeys");
|
||||
const generator = this.#checkGenerator();
|
||||
const [privateKey, publicKey] = ops.op_node_dh_generate2(
|
||||
this.#prime,
|
||||
this.#primeLength,
|
||||
generator,
|
||||
);
|
||||
|
||||
this.#privateKey = Buffer.from(privateKey.buffer);
|
||||
this.#publicKey = Buffer.from(publicKey.buffer);
|
||||
|
||||
return this.#publicKey;
|
||||
}
|
||||
|
||||
getGenerator(): Buffer;
|
||||
getGenerator(encoding: BinaryToTextEncoding): string;
|
||||
getGenerator(_encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.getGenerator");
|
||||
getGenerator(encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
if (encoding !== undefined && encoding != "buffer") {
|
||||
return this.#generator.toString(encoding);
|
||||
}
|
||||
|
||||
return this.#generator;
|
||||
}
|
||||
|
||||
getPrime(): Buffer;
|
||||
getPrime(encoding: BinaryToTextEncoding): string;
|
||||
getPrime(_encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.getPrime");
|
||||
getPrime(encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
if (encoding !== undefined && encoding != "buffer") {
|
||||
return this.#prime.toString(encoding);
|
||||
}
|
||||
|
||||
return this.#prime;
|
||||
}
|
||||
|
||||
getPrivateKey(): Buffer;
|
||||
getPrivateKey(encoding: BinaryToTextEncoding): string;
|
||||
getPrivateKey(_encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.getPrivateKey");
|
||||
getPrivateKey(encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
if (encoding !== undefined && encoding != "buffer") {
|
||||
return this.#privateKey.toString(encoding);
|
||||
}
|
||||
|
||||
return this.#privateKey;
|
||||
}
|
||||
|
||||
getPublicKey(): Buffer;
|
||||
getPublicKey(encoding: BinaryToTextEncoding): string;
|
||||
getPublicKey(_encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
notImplemented("crypto.DiffieHellman.prototype.getPublicKey");
|
||||
getPublicKey(encoding?: BinaryToTextEncoding): Buffer | string {
|
||||
if (encoding !== undefined && encoding != "buffer") {
|
||||
return this.#publicKey.toString(encoding);
|
||||
}
|
||||
|
||||
return this.#publicKey;
|
||||
}
|
||||
|
||||
setPrivateKey(privateKey: ArrayBufferView): void;
|
||||
setPrivateKey(privateKey: string, encoding: BufferEncoding): void;
|
||||
setPrivateKey(
|
||||
_privateKey: ArrayBufferView | string,
|
||||
_encoding?: BufferEncoding,
|
||||
privateKey: ArrayBufferView | string,
|
||||
encoding?: BufferEncoding,
|
||||
) {
|
||||
notImplemented("crypto.DiffieHellman.prototype.setPrivateKey");
|
||||
if (encoding == undefined || encoding == "buffer") {
|
||||
this.#privateKey = Buffer.from(privateKey);
|
||||
} else {
|
||||
this.#privateKey = Buffer.from(privateKey, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
setPublicKey(publicKey: ArrayBufferView): void;
|
||||
setPublicKey(publicKey: string, encoding: BufferEncoding): void;
|
||||
setPublicKey(
|
||||
_publicKey: ArrayBufferView | string,
|
||||
_encoding?: BufferEncoding,
|
||||
publicKey: ArrayBufferView | string,
|
||||
encoding?: BufferEncoding,
|
||||
) {
|
||||
notImplemented("crypto.DiffieHellman.prototype.setPublicKey");
|
||||
if (encoding == undefined || encoding == "buffer") {
|
||||
this.#publicKey = Buffer.from(publicKey);
|
||||
} else {
|
||||
this.#publicKey = Buffer.from(publicKey, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
NOTE: This file should not be manually edited. Please edit 'cli/tests/node_compat/config.json' and run 'tools/node_compat/setup.ts' instead.
|
||||
|
||||
Total: 2935
|
||||
Total: 2934
|
||||
|
||||
- [abort/test-abort-backtrace.js](https://github.com/nodejs/node/tree/v18.12.1/test/abort/test-abort-backtrace.js)
|
||||
- [abort/test-abort-fatal-error.js](https://github.com/nodejs/node/tree/v18.12.1/test/abort/test-abort-fatal-error.js)
|
||||
|
@ -476,7 +476,6 @@ Total: 2935
|
|||
- [parallel/test-crypto-dh-padding.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-dh-padding.js)
|
||||
- [parallel/test-crypto-dh-shared.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-dh-shared.js)
|
||||
- [parallel/test-crypto-dh-stateless.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-dh-stateless.js)
|
||||
- [parallel/test-crypto-dh.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-dh.js)
|
||||
- [parallel/test-crypto-domain.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-domain.js)
|
||||
- [parallel/test-crypto-domains.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-domains.js)
|
||||
- [parallel/test-crypto-ecb.js](https://github.com/nodejs/node/tree/v18.12.1/test/parallel/test-crypto-ecb.js)
|
||||
|
|
Loading…
Reference in a new issue