Zum Inhalt springen
ecdsa.com
Node.js

node-forge

node-forge von Digital Bazaar, ein TLS-, PKI- und PKCS-Toolkit in reinem JavaScript: RSA, PKCS#12, X.509 und Ed25519 – aber überhaupt kein ECDSA, sodass es weder Schlüssel noch Zertifikate für elliptische Kurven lesen kann.
Lizenz
BSD-3-Clause OR GPL-2.0
Geprüfte Version
1.4.0 ·
Quellcode
github.com/digitalbazaar/forge
Dokumentation
github.com/digitalbazaar/forge#readme

Kompatibilität auf einen Blick

EdDSA

EdDSA
Ed25519

node-forge begann als TLS-Implementierung in JavaScript und wird heute vor allem für seine PKI-Bausteine genutzt: Erzeugen und Parsen von X.509-Zertifikaten und CSRs, Lesen und Schreiben von PKCS#12-Bundles, RSA-Verschlüsselung und -Signaturen sowie ein ASN.1-Parser. Es läuft in Browsern und in Node.js gleich und enthält keinen nativen Code.

Über Ed25519 hinaus unterstützt es keine elliptischen Kurven. forge.pki stellt nur rsa und ed25519 bereit, und der Test bestätigte die Folge: certificateFromPem() wirft bei einem ECDSA-Zertifikat Cannot read public key. OID is not RSA., und publicKeyFromPem() wirft bei einem öffentlichen Schlüssel vom Typ EC Cannot read public key. Unknown OID. – obwohl sich dieselben Bytes mit dem eigenen ASN.1-Reader von forge problemlos parsen lassen. Code, der Zertifikate aus der Praxis untersucht, trifft ständig auf ECDSA-Schlüssel und braucht dafür einen anderen Parser; X509Certificate aus node:crypto oder der Zertifikats-Decoder kommen mit beiden Schlüsseltypen zurecht.

Bei RSA klappt das Zusammenspiel reibungslos, sobald die Parameter übereinstimmen. Von forge erzeugte Signaturen nach PKCS#1 v1.5 und PSS bestanden die Prüfung mit node:crypto; bei PSS müssen der Digest, der MGF1-Digest und die Salt-Länge auf beiden Seiten übereinstimmen, und forge verlangt, dass du alle drei angibst, wie es das Beispiel tut. Öffentliche Schlüssel lassen sich aus SPKI-, PKCS#1- und Zertifikats-PEM laden, private Schlüssel aus PKCS#8, verschlüsseltem PKCS#8, PKCS#1 und PKCS#12 – öffne Bundles im PFX-Inspektor, um zu sehen, was sie enthalten.

Ed25519-Signaturen von forge waren beim selben Seed byteidentisch mit denen von node:crypto. Der private Schlüssel liegt in forge in der erweiterten 64-Byte-Form vor (der Seed, gefolgt vom öffentlichen Schlüssel), sodass Bibliotheken, die den 32-Byte-Seed erwarten, nur die erste Hälfte brauchen.

Bei der Signaturprüfung waren die Parser schon mehrfach zu nachsichtig, und ein Fall ist noch offen. Das Advisory GHSA-86w9-cpqp-85rv (CVE-2026-85393), veröffentlicht im September 2026 ohne korrigiertes Release, meldet, dass die Prüfung von RSA-Signaturen nach PKCS#1 v1.5 in Versionen bis einschließlich 1.4.0 zusätzliche Elemente im Algorithmusbezeichner der DigestInfo ignoriert; dadurch lassen sich Signaturen für Schlüssel mit einem kleinen öffentlichen Exponenten wie 3 fälschen. Der Test reproduzierte diese Nachsicht: Ein Block mit korrektem Padding und einem zusätzlichen Element an dieser Stelle bestand die Prüfung in forge und wurde von node:crypto abgelehnt. Bis eine Korrektur erscheint, prüfe PKCS#1-v1.5-Signaturen mit node:crypto oder WebCrypto und vermeide RSA-Schlüssel mit dem Exponenten 3. Version 1.4.0 selbst behob die vorherige Runde – ein zusätzliches Feld nach dem Digest und nicht kanonische Ed25519-Signaturen wurden beide abgelehnt –, und Versionen vor 1.3.0 hatten frühere Fehler, die Signaturfälschungen ermöglichten (CVE-2022-24771, CVE-2022-24772).

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/node-forge/run.sh hat node-forge 1.4.0 unter Node.js 24.22.0 am 20. Oktober 2026 im Container-Image node:24.22.0-bookworm-slim ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • ECDSA-Kurven

    none

    Keine ECDSA-Implementierung: forge.pki enthält rsa und ed25519 und nichts für NIST-Kurven oder secp256k1.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = none
    evidence ecdsa-curves: forge.pki members: ed25519, rsa
  • Zertifikate mit EC-Schlüsseln

    rejected

    certificateFromPem() wirft bei einem P-256-Zertifikat Cannot read public key. OID is not RSA.; ein öffentlicher Schlüssel vom Typ EC führt zu Cannot read public key. Unknown OID.

    Von der Prüfung aufgezeichnet
    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 über forge.pki.ed25519.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519
  • Ed25519 entspricht RFC 8032

    yes

    Beim selben 32-Byte-Seed erzeugte forge genau die Signatur, die auch node:crypto erzeugte, wie es das deterministische Verfahren aus RFC 8032 verlangt.

    Von der Prüfung aufgezeichnet
    fact ed25519-matches-rfc8032 = yes
    evidence ed25519-matches-rfc8032: forge and node:crypto signatures for the same seed are identical: true
  • Aufbau des privaten Schlüssels (Ed25519)

    expanded-64

    Private Schlüssel für Ed25519 umfassen 64 Byte: den Seed, gefolgt vom öffentlichen Schlüssel.

    Von der Prüfung aufgezeichnet
    fact ed25519-private-key = expanded-64
  • Ed25519-Signatur mit nicht kanonischem S

    rejected

    Eine Ed25519-Signatur, in der S durch S + L ersetzt war – die durch Malleability veränderte Form, die RFC 8032 verbietet –, wurde abgelehnt, ebenso wie von node:crypto; diese Prüfung kam mit 1.4.0 hinzu (CVE-2026-33895).

    Von der Prüfung aufgezeichnet
    fact ed25519-non-canonical-s = rejected
    evidence ed25519-non-canonical-s: forge: false; node:crypto: false
  • Post-Quanten-Algorithmen

    none

    Keine Post-Quanten-Algorithmen.

    Von der Prüfung aufgezeichnet
    fact pqc = none
  • RSA-Signaturverfahren

    PKCS1-v1_5PSS

    Mit SHA-256 erstellte Signaturen nach PKCS#1 v1.5 und PSS bestanden die Prüfung in node:crypto; PSS verlangt eine ausdrücklich angegebene Salt-Länge und einen MGF1-Digest.

    Von der Prüfung aufgezeichnet
    fact rsa-signature-schemes = PKCS1-v1_5, PSS
  • Zusätzliches Element in einer DigestInfo nach PKCS #1

    accepted-in-algorithm-identifier

    Ein PKCS#1-v1.5-Block mit einem zusätzlichen Element im AlgorithmIdentifier der DigestInfo bestand die Prüfung in forge, aber nicht in node:crypto; ein zusätzliches Element nach dem Digest wurde abgelehnt. Das ist das offene Advisory GHSA-86w9-cpqp-85rv.

    Von der Prüfung aufgezeichnet
    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
  • Formate öffentlicher Schlüssel (RSA)

    spki-pempkcs1x509

    Öffentliche Schlüssel für RSA ließen sich aus SPKI-PEM, PKCS#1-PEM (RSA PUBLIC KEY) und Zertifikaten laden.

    Von der Prüfung aufgezeichnet
    fact rsa-public-key-formats = spki-pem, pkcs1, x509
  • Formate privater Schlüssel (RSA)

    pkcs8-pemencrypted-pkcs8pkcs1pkcs12

    Private Schlüssel für RSA ließen sich aus PKCS#8-PEM, verschlüsseltem PKCS#8 (decryptRsaPrivateKey), PKCS#1-PEM (RSA PRIVATE KEY) und PKCS#12 laden.

    Von der Prüfung aufgezeichnet
    fact rsa-private-key-formats = pkcs8-pem, encrypted-pkcs8, pkcs1, pkcs12

Verwendung

Signiere in forge mit RSA-PSS, prüfe in node:crypto mit denselben Parametern und zeige dann, was mit einem EC-Schlüssel passiert.
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);
}

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image node:24.22.0-bookworm-slim aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
npm init -y >/dev/null && npm install --no-audit --no-fund node-forge@1.4.0
Befehl
node usage.mjs
Ausgabe muss passen (regulärer Ausdruck)
PSS verified by node:crypto: true\nEC key: Cannot read public key\. Unknown OID\.

Bibliotheken