O Network Security Services é a biblioteca por baixo do Firefox, do Thunderbird e de vários componentes de sistema do Linux, incluindo o WebCrypto do Firefox. Ele funciona por meio do PKCS#11: as chaves ficam em um token (o softoken embutido, um smart card ou um HSM), e tudo acima dele chama as funções PK11_*. Os fatos desta página foram verificados no pacote do Alpine 3.24.2, NSS 3.124, inicializado sem banco de dados de chaves (NSS_NoDB_Init).
O ECDSA tem duas camadas que produzem codificações diferentes. SEC_SignData e VFY_VerifyData, no cryptohi, calculam o hash da mensagem e usam DER, a forma que X.509, CMS e OpenSSL esperam. PK11_Sign e PK11_Verify recebem um digest e usam a forma r‖s bruta, 64 bytes na P-256. Misturar as duas é o erro clássico com o NSS; converta com o conversor DER ⇄ bruto. PK11_Sign também aceitou um digest de 64 bytes na P-256 e assinou os primeiros 32 bytes dele, então passe um digest compatível com a curva.
Os nonces são aleatórios — duas assinaturas da mesma mensagem foram diferentes — e o s não é normalizado; uma assinatura high-S passou na verificação. O ECDSA com SHA-256 assinou e verificou com uma chave P-384, então o hash não está vinculado à curva. As falhas podem ser distinguidas: depois que VFY_VerifyData retorna SECFailure, PORT_GetError() informa SEC_ERROR_BAD_DER para uma assinatura bruta ou truncada e SEC_ERROR_BAD_SIGNATURE para uma assinatura válida sobre outros dados.
O softoken gerou chaves apenas na P-256, na P-384 e na P-521; P-224 e secp256k1 falharam com SEC_ERROR_INVALID_KEY. O Ed25519 funciona por meio de CKM_EC_EDWARDS_KEY_PAIR_GEN e CKM_EDDSA; o Ed448, não. O encapsulamento ML-KEM-768 faz o ciclo completo de ida e volta (PK11_Encapsulate, PK11_Decapsulate), enquanto os arquivos de cabeçalho declaram mecanismos ML-DSA que o softoken deste build não oferece. Compare o KEM na ferramenta de ML-KEM.