Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions deps/ncrypto/ncrypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3103,9 +3103,13 @@ const Cipher Cipher::AES_256_GCM = Cipher::FromNid(NID_aes_256_gcm);
const Cipher Cipher::AES_128_KW = Cipher::FromNid(NID_id_aes128_wrap);
const Cipher Cipher::AES_192_KW = Cipher::FromNid(NID_id_aes192_wrap);
const Cipher Cipher::AES_256_KW = Cipher::FromNid(NID_id_aes256_wrap);

#ifndef OPENSSL_IS_BORINGSSL
const Cipher Cipher::AES_128_OCB = Cipher::FromNid(NID_aes_128_ocb);
const Cipher Cipher::AES_192_OCB = Cipher::FromNid(NID_aes_192_ocb);
const Cipher Cipher::AES_256_OCB = Cipher::FromNid(NID_aes_256_ocb);
#endif

const Cipher Cipher::CHACHA20_POLY1305 = Cipher::FromNid(NID_chacha20_poly1305);

bool Cipher::isGcmMode() const {
Expand Down
9 changes: 6 additions & 3 deletions deps/ncrypto/ncrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,9 +309,12 @@ class Cipher final {
#else
static constexpr size_t MAX_AUTH_TAG_LENGTH = 16;
#endif
static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH);
static_assert(EVP_GCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH
#ifndef OPENSSL_IS_BORINGSSL
&& EVP_CCM_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH &&
EVP_CHACHAPOLY_TLS_TAG_LEN <= MAX_AUTH_TAG_LENGTH
#endif
); // NOLINT(whitespace/parens)

Cipher() = default;
Cipher(const EVP_CIPHER* cipher) : cipher_(cipher) {}
Expand Down
2 changes: 2 additions & 0 deletions src/crypto/crypto_cipher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,10 @@ bool CipherBase::InitAuthenticated(const char* cipher_type,
// Other modes (CCM, OCB) require an explicit tag length.
if (ctx_.isGcmMode()) {
auth_tag_len = EVP_GCM_TLS_TAG_LEN;
#ifdef EVP_CHACHAPOLY_TLS_TAG_LEN
} else if (ctx_.isChaCha20Poly1305()) {
auth_tag_len = EVP_CHACHAPOLY_TLS_TAG_LEN;
#endif
} else {
THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
env(), "authTagLength required for %s", cipher_type);
Expand Down
5 changes: 5 additions & 0 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1928,8 +1928,13 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
// true to this function instead of the original string. Any other string
// value will be interpreted as custom DH parameters below.
if (args[0]->IsTrue()) {
#ifdef SSL_CTX_set_dh_auto
CHECK(SSL_CTX_set_dh_auto(sc->ctx_.get(), true));
return;
#else
return THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(
env, "Automatic DH parameter selection is not supported");
#endif
}

DHPointer dh;
Expand Down
6 changes: 4 additions & 2 deletions src/crypto/crypto_dh.cc
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,17 @@ void ComputeSecret(const FunctionCallbackInfo<Value>& args) {
BignumPointer key(key_buf.data(), key_buf.size());

switch (dh.checkPublicKey(key)) {
case DHPointer::CheckPublicKeyResult::INVALID:
// Fall-through
case DHPointer::CheckPublicKeyResult::CHECK_FAILED:
return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env,
"Unspecified validation error");
#ifndef OPENSSL_IS_BORINGSSL
case DHPointer::CheckPublicKeyResult::TOO_SMALL:
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too small");
case DHPointer::CheckPublicKeyResult::TOO_LARGE:
return THROW_ERR_CRYPTO_INVALID_KEYLEN(env, "Supplied key is too large");
#endif
case DHPointer::CheckPublicKeyResult::INVALID:
return THROW_ERR_CRYPTO_INVALID_KEYTYPE(env, "Supplied key is invalid");
case DHPointer::CheckPublicKeyResult::NONE:
break;
}
Expand Down
12 changes: 12 additions & 0 deletions src/crypto/crypto_rsa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,18 @@ Maybe<void> RsaKeyGenTraits::AdditionalConfig(
params->params.modulus_bits = args[*offset + 1].As<Uint32>()->Value();
params->params.exponent = args[*offset + 2].As<Uint32>()->Value();

#ifdef OPENSSL_IS_BORINGSSL
// BoringSSL hangs indefinitely generating an RSA key with e=1, and for
// other invalid exponents (e=0, even values) reports the misleading error
// RSA_R_TOO_MANY_ITERATIONS only after running the full keygen loop. Reject
// those up-front with a clear error. The constraint here (odd integer >= 3)
// matches BoringSSL's own rsa_check_public_key validation.
if (params->params.exponent < 3 || (params->params.exponent & 1) == 0) {
THROW_ERR_OUT_OF_RANGE(env, "publicExponent is invalid");
return Nothing<void>();
}
#endif

*offset += 3;

if (params->params.variant == kKeyVariantRSA_PSS) {
Expand Down
84 changes: 46 additions & 38 deletions src/crypto/crypto_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -553,44 +553,51 @@ Maybe<void> Decorate(Environment* env,
c = ToUpper(c);
}

#define OSSL_ERROR_CODES_MAP(V) \
V(SYS) \
V(BN) \
V(RSA) \
V(DH) \
V(EVP) \
V(BUF) \
V(OBJ) \
V(PEM) \
V(DSA) \
V(X509) \
V(ASN1) \
V(CONF) \
V(CRYPTO) \
V(EC) \
V(SSL) \
V(BIO) \
V(PKCS7) \
V(X509V3) \
V(PKCS12) \
V(RAND) \
V(DSO) \
V(ENGINE) \
V(OCSP) \
V(UI) \
V(COMP) \
V(ECDSA) \
V(ECDH) \
V(OSSL_STORE) \
V(FIPS) \
V(CMS) \
V(TS) \
V(HMAC) \
V(CT) \
V(ASYNC) \
V(KDF) \
V(SM2) \
V(USER) \
#ifdef OPENSSL_IS_BORINGSSL
#define OSSL_ERROR_CODES_MAP_OPENSSL_ONLY(V)
#else
#define OSSL_ERROR_CODES_MAP_OPENSSL_ONLY(V) \
V(PKCS12) \
V(DSO) \
V(OSSL_STORE) \
V(FIPS) \
V(TS) \
V(CT) \
V(ASYNC) \
V(KDF) \
V(SM2)
#endif

#define OSSL_ERROR_CODES_MAP(V) \
V(SYS) \
V(BN) \
V(RSA) \
V(DH) \
V(EVP) \
V(BUF) \
V(OBJ) \
V(PEM) \
V(DSA) \
V(X509) \
V(ASN1) \
V(CONF) \
V(CRYPTO) \
V(EC) \
V(SSL) \
V(BIO) \
V(PKCS7) \
V(X509V3) \
V(RAND) \
V(ENGINE) \
V(OCSP) \
V(UI) \
V(COMP) \
V(ECDSA) \
V(ECDH) \
V(CMS) \
V(HMAC) \
V(USER) \
OSSL_ERROR_CODES_MAP_OPENSSL_ONLY(V)

#define V(name) case ERR_LIB_##name: lib = #name "_"; break;
const char* lib = "";
Expand All @@ -600,6 +607,7 @@ Maybe<void> Decorate(Environment* env,
}
#undef V
#undef OSSL_ERROR_CODES_MAP
#undef OSSL_ERROR_CODES_MAP_OPENSSL_ONLY
// Don't generate codes like "ERR_OSSL_SSL_".
if (lib && strcmp(lib, "SSL_") == 0)
prefix = "";
Expand Down
20 changes: 11 additions & 9 deletions test/parallel/test-crypto-async-sign-verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,19 @@ if (!process.features.openssl_is_boringssl) {
// ECDSA w/ ieee-p1363 signature encoding
test('ec_secp256k1_public.pem', 'ec_secp256k1_private.pem', 'sha384', false,
{ dsaEncoding: 'ieee-p1363' });
}

// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
false);
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
false, { dsaEncoding: 'der' });
// DSA w/ der signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
false);
test('dsa_public.pem', 'dsa_private.pem', 'sha256',
false, { dsaEncoding: 'der' });

// DSA w/ ieee-p1363 signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256', false,
{ dsaEncoding: 'ieee-p1363' });
// DSA w/ ieee-p1363 signature encoding
test('dsa_public.pem', 'dsa_private.pem', 'sha256', false,
{ dsaEncoding: 'ieee-p1363' });
} else {
common.printSkipMessage('Skipping unsupported ed448/secp256k1/dsa test cases');
}

// Test Parallel Execution w/ KeyObject is threadsafe in openssl3
{
Expand Down
47 changes: 30 additions & 17 deletions test/parallel/test-crypto-authenticated.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,22 +626,25 @@ for (const test of TEST_CASES) {

{
// CCM cipher without data should not crash, see https://github.com/nodejs/node/issues/38035.
const algo = 'aes-128-ccm';
const key = Buffer.alloc(16);
const iv = Buffer.alloc(12);
const opts = { authTagLength: 10 };
if (!ciphers.includes('aes-128-ccm')) {
common.printSkipMessage(`unsupported aes-128-ccm test`);
} else {
const key = Buffer.alloc(16);
const iv = Buffer.alloc(12);
const opts = { authTagLength: 10 };

const cipher = crypto.createCipheriv(algo, key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
const cipher = crypto.createCipheriv('aes-128-ccm', key, iv, opts);
assert.throws(() => {
cipher.final();
}, hasOpenSSL3 ? {
code: 'ERR_OSSL_TAG_NOT_SET'
} : {
message: /Unsupported state/
});
}
}

{
if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand All @@ -653,11 +656,13 @@ for (const test of TEST_CASES) {
message: errMessages.authTagLength
});
}
} else {
common.printSkipMessage('Skipping unsupported chacha20-poly1305 test');
}

// ChaCha20-Poly1305 should respect the authTagLength option and should not
// require the authentication tag before calls to update() during decryption.
{
if (!process.features.openssl_is_boringssl) {
const key = Buffer.alloc(32);
const iv = Buffer.alloc(12);

Expand Down Expand Up @@ -697,6 +702,8 @@ for (const test of TEST_CASES) {
}
}
}
} else {
common.printSkipMessage('Skipping unsupported chacha20-poly1305 test');
}

// ChaCha20-Poly1305 should default to an authTagLength of 16. When encrypting,
Expand All @@ -706,7 +713,7 @@ for (const test of TEST_CASES) {
// shorter tags as long as their length was valid according to NIST SP 800-38D.
// For ChaCha20-Poly1305, we intentionally deviate from that because there are
// no recommended or approved authentication tag lengths below 16 bytes.
{
if (!process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand Down Expand Up @@ -740,10 +747,12 @@ for (const test of TEST_CASES) {

assert.strictEqual(plaintext.toString('hex'), testCase.plain);
}
} else {
common.printSkipMessage('Skipping unsupported chacha20-poly1305 test');
}

// https://github.com/nodejs/node/issues/45874
{
if (!process.features.openssl_is_boringssl) {
const rfcTestCases = TEST_CASES.filter(({ algo, tampered }) => {
return algo === 'chacha20-poly1305' && tampered === false;
});
Expand Down Expand Up @@ -771,10 +780,12 @@ for (const test of TEST_CASES) {
assert.throws(() => {
decipher.final();
}, /Unsupported state or unable to authenticate data/);
} else {
common.printSkipMessage('Skipping unsupported chacha20-poly1305 test');
}

// Refs: https://github.com/nodejs/node/issues/62342
{
if (ciphers.includes('aes-128-ccm')) {
const key = crypto.randomBytes(16);
const nonce = crypto.randomBytes(13);

Expand All @@ -794,4 +805,6 @@ for (const test of TEST_CASES) {
decipher.setAAD(Buffer.alloc(0), { plaintextLength: 0 });
decipher.update(new DataView(new ArrayBuffer(0)));
decipher.final();
} else {
common.printSkipMessage('Skipping unsupported aes-128-ccm test');
}
4 changes: 4 additions & 0 deletions test/parallel/test-crypto-cipheriv-decipheriv.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ function testCipher2(key, iv) {


function testCipher3(key, iv) {
if (!crypto.getCiphers().includes('id-aes128-wrap')) {
common.printSkipMessage(`unsupported id-aes128-wrap test`);
return;
}
// Test encryption and decryption with explicit key and iv.
// AES Key Wrap test vector comes from RFC3394
const plaintext = Buffer.from('00112233445566778899AABBCCDDEEFF', 'hex');
Expand Down
3 changes: 3 additions & 0 deletions test/parallel/test-crypto-default-shake-lengths-oneshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

if (process.features.openssl_is_boringssl)
common.skip('not supported by BoringSSL');

const { hash } = require('crypto');

common.expectWarning({
Expand Down
4 changes: 3 additions & 1 deletion test/parallel/test-crypto-dh-curves.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const p = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' +
crypto.createDiffieHellman(p, 'hex');

// Confirm DH_check() results are exposed for optional examination.
const bad_dh = crypto.createDiffieHellman('02', 'hex');
const bad_dh = process.features.openssl_is_boringssl ?
crypto.createDiffieHellman('abcd', 'hex', 0) :
crypto.createDiffieHellman('02', 'hex');
assert.notStrictEqual(bad_dh.verifyError, 0);

const availableCurves = new Set(crypto.getCurves());
Expand Down
4 changes: 4 additions & 0 deletions test/parallel/test-crypto-dh-group-setters.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ if (!common.hasCrypto)
const assert = require('assert');
const crypto = require('crypto');

if (process.features.openssl_is_boringssl) {
common.skip('Skipping unsupported Diffie-Hellman tests');
}

// Unlike DiffieHellman, DiffieHellmanGroup does not have any setters.
const dhg = crypto.getDiffieHellman('modp1');
assert.strictEqual(dhg.constructor, crypto.DiffieHellmanGroup);
Expand Down
4 changes: 4 additions & 0 deletions test/parallel/test-crypto-dh-modp2-views.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ const assert = require('assert');
const crypto = require('crypto');
const { modp2buf } = require('../common/crypto');

if (process.features.openssl_is_boringssl) {
common.skip('Skipping unsupported Diffie-Hellman tests');
}

const modp2 = crypto.createDiffieHellmanGroup('modp2');

const views = common.getArrayBufferViews(modp2buf);
Expand Down
5 changes: 5 additions & 0 deletions test/parallel/test-crypto-dh-modp2.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ if (!common.hasCrypto)
const assert = require('assert');
const crypto = require('crypto');
const { modp2buf } = require('../common/crypto');

if (process.features.openssl_is_boringssl) {
common.skip('Skipping unsupported Diffie-Hellman tests');
}

const modp2 = crypto.createDiffieHellmanGroup('modp2');

{
Expand Down
Loading