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.