Zum Inhalt springen
ecdsa.com
C · Befehlszeile

NSS (Network Security Services)

NSS, die Krypto- und TLS-Bibliothek von Mozilla hinter Firefox und Thunderbird: zwei Signaturschichten mit unterschiedlicher ECDSA-Kodierung (DER über cryptohi, rohes r‖s über PK11), nur P-256 bis P-521, Ed25519 und ML-KEM.
Lizenz
MPL-2.0
Geprüfte Version
3.124 ·
Quellcode
hg.mozilla.org/projects/nss
Dokumentation
firefox-source-docs.mozilla.org/security/nss/index.html

Kompatibilität auf einen Blick

ECDSAEdDSAPost-Quanten-Verfahren

ECDSA-Kurven
P-256P-384P-521
EdDSA
Ed25519

Network Security Services ist die Bibliothek hinter Firefox, Thunderbird und mehreren Linux-Systemkomponenten, darunter WebCrypto in Firefox. NSS arbeitet über PKCS#11: Schlüssel liegen in einem Token (im eingebauten Softoken oder auf einer Smartcard oder einem HSM), und alles, was darüber liegt, ruft die Funktionen PK11_* auf. Die Fakten auf dieser Seite wurden mit dem Paket aus Alpine 3.24.2 geprüft, NSS 3.124, initialisiert ohne Schlüsseldatenbank (NSS_NoDB_Init).

ECDSA hat zwei Schichten, die unterschiedliche Kodierungen erzeugen. SEC_SignData und VFY_VerifyData in cryptohi hashen die Nachricht und verwenden DER, die Form, die X.509, CMS und OpenSSL erwarten. PK11_Sign und PK11_Verify nehmen einen Digest entgegen und verwenden die rohe r‖s-Form, auf P-256 64 Byte. Beides zu vermischen ist der klassische Fehler mit NSS; konvertiere mit dem Konverter DER ⇄ Raw. PK11_Sign akzeptierte auf P-256 außerdem einen 64-Byte-Digest und signierte dessen erste 32 Byte; übergib also einen Digest, der zur Kurve passt.

Nonces sind zufällig – zwei Signaturen derselben Nachricht unterschieden sich –, und s wird nicht normalisiert; eine High-S-Signatur bestand die Prüfung. Signieren und Prüfen mit ECDSA und SHA-256 funktionierten mit einem P-384-Schlüssel, der Hash ist also nicht an die Kurve gebunden. Fehlschläge lassen sich unterscheiden: Nachdem VFY_VerifyData SECFailure zurückgegeben hat, meldet PORT_GetError() für eine rohe oder abgeschnittene Signatur SEC_ERROR_BAD_DER und für eine gültige Signatur über andere Daten SEC_ERROR_BAD_SIGNATURE.

Das Softoken erzeugte Schlüssel nur auf P-256, P-384 und P-521; P-224 und secp256k1 scheiterten mit SEC_ERROR_INVALID_KEY. Ed25519 funktioniert über CKM_EC_EDWARDS_KEY_PAIR_GEN und CKM_EDDSA, Ed448 nicht. Die Kapselung mit ML-KEM-768 besteht den Roundtrip (PK11_Encapsulate, PK11_Decapsulate), während die Header ML-DSA-Mechanismen deklarieren, die das Softoken in diesem Build nicht anbietet. Vergleiche das KEM mit dem ML-KEM-Tool.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/nss/run.sh hat NSS (Network Security Services) 3.124 am 20. Oktober 2026 im Container-Image alpine:3.24.2 ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • Kodierung von ECDSA-Signaturen

    der-or-raw

    SEC_SignData gab striktes DER zurück; PK11_Sign gab auf P-256 64 Byte rohes r‖s zurück.

    Von der Prüfung aufgezeichnet
    fact ecdsa-signature-encoding = der-or-raw
    evidence ecdsa-signature-encoding: SEC_SignData output parses as strict DER: yes; PK11_Sign: 64 bytes (P-256 raw r||s is 64)
  • ECDSA-Nonce

    random

    Zwei Signaturen derselben Nachricht mit SEC_SignData waren verschieden.

    Von der Prüfung aufgezeichnet
    fact ecdsa-nonce = random
    evidence ecdsa-nonce: two SEC_SignData signatures of one message are different
  • Low-S beim Signieren

    either

    s wird nicht normalisiert: Unter 64 Signaturen traten High-S-Werte auf.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-sign = either
    evidence ecdsa-low-s-sign: signatures with s > n/2 among 64: yes
  • High-S bei der Prüfung

    accepts-high-s

    Eine DER-Signatur, in der s durch n − s ersetzt war, bestand die Prüfung mit VFY_VerifyData.

    Von der Prüfung aufgezeichnet
    fact ecdsa-low-s-verify = accepts-high-s
  • Was der Signaturaufruf hasht

    hashes-message-or-digest

    SEC_SignData hasht die Nachricht; PK11_Sign über den SHA-256-Hash der Nachricht erzeugte eine Signatur, die VFY_VerifyData akzeptierte.

    Von der Prüfung aufgezeichnet
    fact ecdsa-prehash = hashes-message-or-digest
    evidence ecdsa-prehash: SEC_SignData hashes the message; PK11_Sign over SHA-256(message) verified with VFY_VerifyData: yes
  • Digest länger als die Kurvenordnung

    truncated

    PK11_Sign akzeptierte auf P-256 einen 64-Byte-Digest; die Signatur bestand die Prüfung über dessen erste 32 Byte.

    Von der Prüfung aufgezeichnet
    fact ecdsa-long-input = truncated
    evidence ecdsa-long-input: PK11_Sign accepted a 64-byte digest; the signature verifies over its first 32 bytes: yes
  • An die Kurve gebundener Hash

    none

    Signieren und Prüfen mit ECDSA und SHA-256 funktionierten mit einem P-384-Schlüssel.

    Von der Prüfung aufgezeichnet
    fact ecdsa-hash-curve-binding = none
    evidence ecdsa-hash-curve-binding: ECDSA with SHA-256 on a P-384 key: sign ok, verify ok
  • Fehlerhafte ECDSA-Signatur

    returns-error

    VFY_VerifyData scheiterte für rohes r‖s und für 3 Byte mit SEC_ERROR_BAD_DER und für eine falsche Nachricht mit SEC_ERROR_BAD_SIGNATURE.

    Von der Prüfung aufgezeichnet
    fact ecdsa-malformed-signature = returns-error
    evidence ecdsa-malformed-signature: VFY_VerifyData returned SECFailure with: raw r||s SEC_ERROR_BAD_DER, 3 bytes SEC_ERROR_BAD_DER, wrong message SEC_ERROR_BAD_SIGNATURE
  • ECDSA-Kurven

    P-256P-384P-521

    P-256, P-384 und P-521; das Erzeugen von Schlüsseln für P-224 und secp256k1 lieferte SEC_ERROR_INVALID_KEY.

    Von der Prüfung aufgezeichnet
    fact ecdsa-curves = P-256, P-384, P-521
    evidence ecdsa-curves: P-224: key generation SEC_ERROR_INVALID_KEY
    evidence ecdsa-curves: secp256k1: key generation SEC_ERROR_INVALID_KEY
  • EdDSA

    Ed25519

    Mit Ed25519 funktionierten Signieren und Prüfen, und zweimaliges Signieren ergab identische Signaturen; das Erzeugen eines Ed448-Schlüssels lieferte SEC_ERROR_INVALID_KEY.

    Von der Prüfung aufgezeichnet
    fact eddsa = Ed25519
    evidence eddsa: Ed25519: keygen ok, sign and verify ok, deterministic yes
    evidence eddsa: Ed448 (OID 1.3.101.113): SEC_ERROR_INVALID_KEY
  • Post-Quanten-Algorithmen

    ML-KEM

    Die Kapselung mit ML-KEM-768 bestand den Roundtrip mit einem 1088 Byte langen Chiffrat; das Erzeugen eines ML-DSA-65-Schlüssels lieferte SEC_ERROR_INVALID_ALGORITHM, und SLH-DSA bietet das Softoken nicht an.

    Von der Prüfung aufgezeichnet
    fact pqc = ML-KEM
    evidence pqc: ML-KEM-768: ciphertext 1088 bytes, shared secrets match: yes
    evidence pqc: ML-DSA-65 key generation failed: SEC_ERROR_INVALID_ALGORITHM; CKM_ML_DSA_KEY_PAIR_GEN in the internal slot: no
    evidence pqc: CKM_SLH_DSA in the internal slot: no

Verwendung

Erzeuge im Softoken einen P-256-Schlüssel, signiere mit `SEC_SignData` und prüfe die DER-Signatur mit `VFY_VerifyData`.
#include <cryptohi.h>
#include <keyhi.h>
#include <nss.h>
#include <pk11pub.h>
#include <secoid.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    NSS_NoDB_Init(NULL);
    /* EC key generation takes the curve OID, DER-encoded, as its parameter. */
    SECOidData *curve = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PRIME256V1);
    unsigned char oid[18] = {0x06, (unsigned char)curve->oid.len};
    memcpy(oid + 2, curve->oid.data, curve->oid.len);
    SECItem params = {siBuffer, oid, curve->oid.len + 2};
    PK11SlotInfo *slot = PK11_GetInternalSlot();
    SECKEYPublicKey *pub = NULL;
    SECKEYPrivateKey *priv = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &params, &pub, PR_FALSE, PR_FALSE, NULL);

    /* SEC_SignData hashes the message and returns DER; PK11_Sign would return raw r||s over a digest. */
    unsigned char msg[] = "order #1042 approved";
    SECItem sig = {siBuffer, NULL, 0};
    SEC_SignData(&sig, msg, sizeof msg - 1, priv, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE);
    SECStatus rv = VFY_VerifyData(msg, sizeof msg - 1, pub, &sig, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, NULL);
    printf("DER tag: 0x%02x, verified: %s\n", sig.data[0], rv == SECSuccess ? "yes" : "no");

    SECITEM_FreeItem(&sig, PR_FALSE);
    SECKEY_DestroyPrivateKey(priv);
    SECKEY_DestroyPublicKey(pub);
    PK11_FreeSlot(slot);
    return NSS_Shutdown() == SECSuccess ? 0 : 1;
}

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

Einrichtung
apk add --no-cache -q build-base nss-dev=3.124-r0 >/dev/null
Befehl
cc -o usage usage.c $(pkg-config --cflags --libs nss) && ./usage
Ausgabe muss passen (regulärer Ausdruck)
DER tag: 0x30, verified: yes

Bibliotheken