Перейти к содержимому
ecdsa.com
C · Командная строка

NSS (Network Security Services)

NSS — библиотека Mozilla для криптографии и TLS, на которой работают Firefox и Thunderbird: два уровня подписи с разной кодировкой ECDSA (DER через cryptohi, raw r‖s через PK11), только кривые от P-256 до P-521, Ed25519 и ML-KEM.
Лицензия
MPL-2.0
Проверенная версия
3.124 ·
Исходный код
hg.mozilla.org/projects/nss
Документация
firefox-source-docs.mozilla.org/security/nss/index.html

Совместимость вкратце

ECDSAEdDSAПостквантовая криптография

Кривые ECDSA
P-256P-384P-521
EdDSA
Ed25519

Network Security Services — библиотека, на которой построены Firefox, Thunderbird и ряд системных компонентов Linux, в том числе WebCrypto в Firefox. Она работает через PKCS#11: ключи хранятся в токене (во встроенном softoken, на смарт-карте или в HSM), а всё, что находится уровнем выше, вызывает функции PK11_*. Факты на этой странице проверены на пакете Alpine 3.24.2 с NSS 3.124, инициализированной без базы ключей (NSS_NoDB_Init).

Для ECDSA есть два уровня, которые выдают разные кодировки. SEC_SignData и VFY_VerifyData из cryptohi хешируют сообщение и используют DER — форму, которую ожидают X.509, CMS и OpenSSL. PK11_Sign и PK11_Verify принимают дайджест и используют форму raw r‖s, 64 байта на P-256. Смешивать их — классическая ошибка при работе с NSS; преобразуйте подпись конвертером DER ⇄ raw. Кроме того, PK11_Sign приняла 64-байтовый дайджест на P-256 и подписала его первые 32 байта, поэтому передавайте дайджест, длина которого соответствует кривой.

Nonce случайны (две подписи одного и того же сообщения различались), а s не нормализуется: подпись с high-S прошла проверку. Подпись и проверка ECDSA с SHA-256 на ключе P-384 прошли успешно, то есть хеш не привязан к кривой. Причины неудачи можно различить: после того как VFY_VerifyData возвращает SECFailure, PORT_GetError() сообщает SEC_ERROR_BAD_DER для подписи raw или усечённой подписи и SEC_ERROR_BAD_SIGNATURE для верной подписи других данных.

Softoken сгенерировал ключи только на P-256, P-384 и P-521; для P-224 и secp256k1 генерация завершилась ошибкой SEC_ERROR_INVALID_KEY. Ed25519 работает через CKM_EC_EDWARDS_KEY_PAIR_GEN и CKM_EDDSA, Ed448 — нет. Инкапсуляция ML-KEM-768 проходит полный цикл (PK11_Encapsulate, PK11_Decapsulate), а механизмы ML-DSA объявлены в заголовочных файлах, но softoken в этой сборке их не предоставляет. Сравните работу KEM в инструменте ML-KEM.

Факты и проверки, на которых они основаны

Ничего из приведённого ниже не скопировано из документации. 20 октября 2026 г. проверка content/libraries/verify/nss/run.sh запустила NSS (Network Security Services) 3.124 в образе контейнера alpine:3.24.2; содержимое страницы должно совпадать с выводом проверки, а у каждого факта приведены соответствующие строки вывода.

  • Кодировка подписи ECDSA

    der-or-raw

    SEC_SignData вернула строгий DER; PK11_Sign вернула 64 байта raw r‖s на P-256.

    Что записала проверка
    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)
  • Nonce в ECDSA

    random

    Две подписи одного сообщения, созданные SEC_SignData, различались.

    Что записала проверка
    fact ecdsa-nonce = random
    evidence ecdsa-nonce: two SEC_SignData signatures of one message are different
  • Low-S при подписи

    either

    s не нормализуется: среди 64 подписей встретились значения high-S.

    Что записала проверка
    fact ecdsa-low-s-sign = either
    evidence ecdsa-low-s-sign: signatures with s > n/2 among 64: yes
  • High-S при проверке

    accepts-high-s

    Подпись в DER, в которой s заменили на n − s, прошла проверку в VFY_VerifyData.

    Что записала проверка
    fact ecdsa-low-s-verify = accepts-high-s
  • Что хеширует вызов подписи

    hashes-message-or-digest

    SEC_SignData хеширует сообщение; PK11_Sign по SHA-256 от сообщения создала подпись, которую VFY_VerifyData приняла.

    Что записала проверка
    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
  • Дайджест длиннее порядка кривой

    truncated

    PK11_Sign приняла 64-байтовый дайджест на P-256; подпись прошла проверку по его первым 32 байтам.

    Что записала проверка
    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
  • Хеш-функция, привязанная к кривой

    none

    Подпись и проверка ECDSA с SHA-256 на ключе P-384 прошли успешно.

    Что записала проверка
    fact ecdsa-hash-curve-binding = none
    evidence ecdsa-hash-curve-binding: ECDSA with SHA-256 on a P-384 key: sign ok, verify ok
  • Некорректная подпись ECDSA

    returns-error

    VFY_VerifyData завершилась ошибкой SEC_ERROR_BAD_DER для raw r‖s и для 3-байтового фрагмента данных, а для неверного сообщения — ошибкой SEC_ERROR_BAD_SIGNATURE.

    Что записала проверка
    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

    P-256P-384P-521

    P-256, P-384 и P-521; генерация ключей P-224 и secp256k1 вернула SEC_ERROR_INVALID_KEY.

    Что записала проверка
    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

    Ed25519 подписал и проверил данные, а две его подписи оказались одинаковыми; генерация ключа Ed448 вернула SEC_ERROR_INVALID_KEY.

    Что записала проверка
    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
  • Постквантовые алгоритмы

    ML-KEM

    Инкапсуляция ML-KEM-768 прошла полный цикл с шифртекстом длиной 1088 байт; генерация ключа ML-DSA-65 вернула SEC_ERROR_INVALID_ALGORITHM, а SLH-DSA в softoken не предоставляется.

    Что записала проверка
    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

Использование

Сгенерируйте ключ P-256 в softoken, подпишите данные через `SEC_SignData` и проверьте подпись в DER через `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;
}

Тестовый стенд для фрагментов кода запускает каждый пример без изменений в образе контейнера alpine:3.24.2, и запуск завершается ошибкой, если вывод не совпадает.

Подготовка
apk add --no-cache -q build-base nss-dev=3.124-r0 >/dev/null
Команда
cc -o usage usage.c $(pkg-config --cflags --libs nss) && ./usage
Вывод должен совпадать (регулярное выражение)
DER tag: 0x30, verified: yes

Библиотеки