Pular para o conteúdo
ecdsa.com
Node.js

node-forge

O node-forge, da Digital Bazaar, um kit de ferramentas de TLS, PKI e PKCS em JavaScript puro: RSA, PKCS#12, X.509 e Ed25519 — mas nenhum suporte a ECDSA, então ele não consegue ler uma chave nem um certificado de curva elíptica.
Licença
BSD-3-Clause OR GPL-2.0
Versão verificada
1.4.0 ·
Código-fonte
github.com/digitalbazaar/forge
Documentação
github.com/digitalbazaar/forge#readme

Visão geral da compatibilidade

EdDSA

EdDSA
Ed25519

O node-forge nasceu como uma implementação de TLS em JavaScript e hoje é usado principalmente pelas partes de PKI: gerar e analisar certificados X.509 e CSRs, ler e gravar pacotes PKCS#12, criptografia e assinaturas RSA e um parser ASN.1. Ele funciona da mesma forma em navegadores e no Node.js e não tem código nativo.

Ele não oferece suporte a curvas elípticas além do Ed25519. forge.pki expõe apenas rsa e ed25519, e o teste confirmou a consequência: certificateFromPem() em um certificado ECDSA lança Cannot read public key. OID is not RSA., e publicKeyFromPem() em uma chave pública EC lança Cannot read public key. Unknown OID. — embora os mesmos bytes sejam analisados sem problemas pelo próprio leitor ASN.1 do forge. Código que inspeciona certificados do mundo real se depara com chaves ECDSA o tempo todo e precisa de outro parser para elas; o X509Certificate do node:crypto ou o decodificador de certificados lidam com os dois tipos de chave.

Com RSA, ele interopera sem problemas quando os parâmetros coincidem. Assinaturas PKCS#1 v1.5 e PSS feitas pelo forge foram verificadas com o node:crypto; o PSS exige que o digest, o digest do MGF1 e o tamanho do salt coincidam nos dois lados, e o forge obriga você a indicar os três, como faz o exemplo. As chaves públicas são carregadas de PEM SPKI, PKCS#1 e de certificado, e as chaves privadas, de PKCS#8, PKCS#8 criptografado, PKCS#1 e PKCS#12 — abra os pacotes PKCS#12 no inspetor de PFX para ver o que contêm.

As assinaturas Ed25519 do forge foram idênticas, byte a byte, às do node:crypto para a mesma semente. A chave privada dele é a forma expandida de 64 bytes — a semente seguida da chave pública —, então bibliotecas que esperam a semente de 32 bytes precisam apenas da primeira metade.

A verificação de assinaturas tem um histórico de parser permissivo demais, e um caso continua em aberto. O alerta de segurança GHSA-86w9-cpqp-85rv (CVE-2026-85393), publicado em setembro de 2026 sem versão corrigida, relata que a verificação RSA PKCS#1 v1.5 nas versões até a 1.4.0 ignora elementos extras dentro do identificador de algoritmo do DigestInfo, o que permite falsificar assinaturas sob chaves com expoente público pequeno, como 3. O teste reproduziu essa permissividade: um bloco com padding correto e um elemento extra nesse ponto foi verificado no forge e rejeitado pelo node:crypto. Até que saia uma correção, verifique assinaturas PKCS#1 v1.5 com o node:crypto ou o WebCrypto e evite chaves RSA com expoente 3. A própria 1.4.0 corrigiu a rodada anterior — um campo extra depois do digest e assinaturas Ed25519 não canônicas passaram a ser rejeitados —, e as versões anteriores à 1.3.0 já tinham outros bugs de falsificação de assinaturas (CVE-2022-24771, CVE-2022-24772).

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/node-forge/run.sh executou node-forge 1.4.0 em Node.js 24.22.0 na imagem de contêiner node:24.22.0-bookworm-slim em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Curvas ECDSA

    none

    Sem implementação de ECDSA: forge.pki tem rsa e ed25519 e nada para as curvas do NIST nem para secp256k1.

    Registrado pela verificação
    fact ecdsa-curves = none
    evidence ecdsa-curves: forge.pki members: ed25519, rsa
  • Certificados com chaves EC

    rejected

    certificateFromPem() em um certificado P-256 lança Cannot read public key. OID is not RSA.; com uma chave pública EC, a exceção é Cannot read public key. Unknown OID.

    Registrado pela verificação
    fact ec-certificate = rejected
    evidence ec-certificate: Cannot read public key. OID is not RSA.
    evidence ec-certificate: the same certificate parses at the ASN.1 level: true
    evidence ec-certificate: publicKeyFromPem on an EC SPKI: Cannot read public key. Unknown OID.
  • EdDSA

    Ed25519

    Ed25519 por meio de forge.pki.ed25519.

    Registrado pela verificação
    fact eddsa = Ed25519
  • Ed25519 conforme a RFC 8032

    yes

    Para a mesma semente de 32 bytes, o forge produziu exatamente a mesma assinatura que o node:crypto, como exige o esquema determinístico da RFC 8032.

    Registrado pela verificação
    fact ed25519-matches-rfc8032 = yes
    evidence ed25519-matches-rfc8032: forge and node:crypto signatures for the same seed are identical: true
  • Estrutura da chave privada Ed25519

    expanded-64

    As chaves privadas Ed25519 têm 64 bytes: a semente seguida da chave pública.

    Registrado pela verificação
    fact ed25519-private-key = expanded-64
  • Assinatura Ed25519 com S não canônico

    rejected

    Uma assinatura Ed25519 cujo S foi substituído por S + L — a forma maleável que a RFC 8032 proíbe — foi rejeitada, assim como no node:crypto; a 1.4.0 acrescentou essa verificação (CVE-2026-33895).

    Registrado pela verificação
    fact ed25519-non-canonical-s = rejected
    evidence ed25519-non-canonical-s: forge: false; node:crypto: false
  • Algoritmos pós-quânticos

    none

    Nenhum algoritmo pós-quântico.

    Registrado pela verificação
    fact pqc = none
  • Esquemas de assinatura RSA

    PKCS1-v1_5PSS

    Assinaturas PKCS#1 v1.5 e PSS feitas com SHA-256 foram verificadas no node:crypto; o PSS exige tamanho de salt e digest do MGF1 explícitos.

    Registrado pela verificação
    fact rsa-signature-schemes = PKCS1-v1_5, PSS
  • Elemento extra em um DigestInfo do PKCS #1

    accepted-in-algorithm-identifier

    Um bloco PKCS#1 v1.5 com um elemento extra dentro do AlgorithmIdentifier do DigestInfo foi verificado no forge, mas não no node:crypto; um elemento extra depois do digest foi rejeitado. Esse é o alerta de segurança em aberto GHSA-86w9-cpqp-85rv.

    Registrado pela verificação
    fact pkcs1-digestinfo-extra-element = accepted-in-algorithm-identifier
    evidence pkcs1-digestinfo-extra-element: well-formed block: forge true, node:crypto true
    evidence pkcs1-digestinfo-extra-element: extra element inside AlgorithmIdentifier: forge true, node:crypto false
    evidence pkcs1-digestinfo-extra-element: extra element after the digest: forge throws ASN.1 object does not contain a valid RSASSA-PKCS1-v1_5 DigestInfo value., node:crypto false
  • Formatos de chave pública RSA

    spki-pempkcs1x509

    Chaves públicas RSA foram carregadas de SPKI em PEM, PKCS#1 RSA PUBLIC KEY em PEM e certificados.

    Registrado pela verificação
    fact rsa-public-key-formats = spki-pem, pkcs1, x509
  • Formatos de chave privada RSA

    pkcs8-pemencrypted-pkcs8pkcs1pkcs12

    Chaves privadas RSA foram carregadas de PKCS#8 em PEM, PKCS#8 criptografado (decryptRsaPrivateKey), PKCS#1 RSA PRIVATE KEY em PEM e PKCS#12.

    Registrado pela verificação
    fact rsa-private-key-formats = pkcs8-pem, encrypted-pkcs8, pkcs1, pkcs12

Uso

Assine com RSA-PSS no forge e verifique no node:crypto com os mesmos parâmetros; depois, mostre o que acontece com uma chave EC.
import { constants, generateKeyPairSync, verify } from "node:crypto";
import forge from "node-forge";

const message = "order #1042 approved";
const { privateKey, publicKey } = generateKeyPairSync("rsa", { modulusLength: 2048 });
const key = forge.pki.privateKeyFromPem(privateKey.export({ type: "pkcs8", format: "pem" }));

// RSA-PSS: SHA-256 for the digest and for MGF1, 32-byte salt. The verifier
// must use the same three parameters.
const sha256 = () => forge.md.sha256.create();
const pss = forge.pss.create({ md: sha256(), mgf: forge.mgf.mgf1.create(sha256()), saltLength: 32 });
const signature = Buffer.from(key.sign(sha256().update(message, "utf8"), pss), "binary");
const options = { key: publicKey, padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: 32 };
console.log("PSS verified by node:crypto:", verify("sha256", Buffer.from(message), options, signature));

// forge has no elliptic-curve support: EC keys and certificates throw.
const ec = generateKeyPairSync("ec", { namedCurve: "P-256" }).publicKey.export({ type: "spki", format: "pem" });
try {
  forge.pki.publicKeyFromPem(ec);
} catch (error) {
  console.log("EC key:", error.message);
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner node:24.22.0-bookworm-slim, e a execução falha se a saída não corresponder.

Configuração
npm init -y >/dev/null && npm install --no-audit --no-fund node-forge@1.4.0
Comando
node usage.mjs
A saída deve corresponder a (expressão regular)
PSS verified by node:crypto: true\nEC key: Cannot read public key\. Unknown OID\.

Bibliotecas