Skip to content

crypto: SM4-GCM and SM4-CCM not available despite OpenSSL 3.5 bundling the implementation #64866

Description

@emmansun

What is the problem this feature will solve?

SM4-GCM and SM4-CCM are documented as available in OpenSSL 3.x default provider (EVP_CIPHER-SM4), and the source files (cipher_sm4_gcm.c, cipher_sm4_ccm.c) are included in Node.js's OpenSSL build (deps/openssl/config/archs/*/openssl.gypi and providers/implementations/ciphers/build.info). However, these ciphers are not registered at runtime.

This affects cross-language interoperability for projects using SM4-GCM (e.g., Java BouncyCastle) that need Node.js decryption support, and China compliance (GM/T 0002) scenarios requiring authenticated encryption with SM4.

Reproduction

const crypto = require('node:crypto');

console.log('Node.js:', process.version);           // v24.18.0
console.log('OpenSSL:', process.versions.openssl);   // 3.5.7
console.log('FIPS:', crypto.getFips());              // 0

// SM4-GCM not in getCiphers()
console.log(crypto.getCiphers().filter(c => c.includes('sm4')));
// → [ 'sm4', 'sm4-cbc', 'sm4-cfb', 'sm4-ctr', 'sm4-ecb', 'sm4-ofb' ]
// Missing: sm4-gcm, sm4-ccm, sm4-xts

// getCipherInfo returns undefined
console.log(crypto.getCipherInfo('sm4-gcm'));   // → undefined
console.log(crypto.getCipherInfo('sm4-cbc'));   // → { mode: 'cbc', nid: 1134, ... }

// createCipheriv throws
try {
  crypto.createCipheriv('sm4-gcm', Buffer.alloc(16), Buffer.alloc(12));
} catch (e) {
  console.log(e.message); // → "Unknown cipher"
}

Evidence that this is a Node.js build issue (not OpenSSL)

  1. OpenSSL docs list SM4-GCM/CCM/XTS as available in the default provider since 3.1+.
  2. Python cryptography library (linking system OpenSSL 3.x) supports SM4-GCM.
  3. Source files are compiled: deps/openssl/config/archs/VC-WAN64A/no-asm/openssl.gypi includes:
    'openssl/providers/implementations/ciphers/cipher_sm4_gcm.c',
    'openssl/providers/implementations/ciphers/cipher_sm4_gcm_hw.c',
    'openssl/providers/implementations/ciphers/cipher_sm4_ccm.c',
    'openssl/providers/implementations/ciphers/cipher_sm4_ccm_hw.c',
    'openssl/providers/implementations/ciphers/cipher_sm4_xts.c',
    'openssl/providers/implementations/ciphers/cipher_sm4_xts_hw.c',
    
  4. build.info includes them unconditionally (given !$disabled{sm4}, and SM4-CBC works).
  5. No no-sm4 in Configure options (deps/openssl/config/Makefile COPTS).

Suspected root cause

Node.js builds OpenSSL with enable-fips. The FIPS module build process may regenerate or filter the default provider's OSSL_ALGORITHM dispatch table, causing SM4-GCM/CCM/XTS registration entries to be dropped while basic SM4 modes (CBC, CTR, ECB, OFB, CFB) are retained.

Additionally, deps/ncrypto/ncrypto.cc line 4304 uses the legacy API:

const Cipher Cipher::FromName(const char* name) {
  return Cipher(EVP_get_cipherbyname(name));
}

Even if the provider registration is fixed, EVP_get_cipherbyname() may not resolve provider-only ciphers that lack a legacy EVP_CIPHER object (per openssl/openssl#13667: "There never will be an evp_sm4_gcm() function"). A fallback to EVP_CIPHER_fetch(NULL, name, NULL) may be needed.

What is the feature you are proposing?

  1. Investigate why SM4-GCM/CCM/XTS are not registered in the default provider at runtime despite being compiled.
  2. If the enable-fips build path is the cause, ensure non-FIPS algorithms remain registered in the default provider.
  3. Consider adding an EVP_CIPHER_fetch fallback in Cipher::FromName() for forward compatibility with provider-only ciphers.

Environment

  • Node.js: v24.18.0
  • OpenSSL: 3.5.7
  • OS: Windows 11 24H2
  • FIPS mode: disabled (0)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions