Pular para o conteúdo
ecdsa.com
C · Linha de comando

GnuTLS

O GnuTLS, a biblioteca TLS e X.509 do projeto GNU: ECDSA em DER nas curvas do NIST, RFC 6979 por meio de uma flag, Ed25519 e Ed448 — e, no build de distribuição verificado, nada de secp256k1 nem de algoritmos pós-quânticos funcionais.
Licença
LGPL-2.1-or-later
Versão verificada
3.8.13 ·
Código-fonte
gitlab.com/gnutls/gnutls
Documentação
www.gnutls.org/manual/

Visão geral da compatibilidade

ECDSAEdDSA

Curvas ECDSA
P-224P-256P-384P-521
EdDSA
Ed25519Ed448

O GnuTLS fornece o tratamento de TLS, X.509 e PKCS para muitos componentes GNU e Linux e inclui o certtool e o gnutls-cli. Suas interfaces abstratas gnutls_privkey_* e gnutls_pubkey_* funcionam da mesma forma para chaves em software, tokens PKCS#11 e TPMs. Os fatos desta página foram verificados no pacote do Alpine 3.24.2, GnuTLS 3.8.13, que usa o Nettle para a aritmética. Desde o GnuTLS 3.8.10, os algoritmos pós-quânticos vêm apenas da biblioteca opcional leancrypto, e este pacote não é vinculado a ela.

gnutls_privkey_sign_data retorna assinaturas ECDSA em DER com um nonce aleatório; a flag GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE muda para a RFC 6979, e com ela o vetor de teste P-256 da RFC foi reproduzido exatamente. O s não é normalizado, e assinaturas high-S passam na verificação. gnutls_privkey_sign_hash2 assina um digest calculado por você.

A verificação retorna um código de erro negativo em caso de falha, e todos os tipos de falha pareceram iguais: uma assinatura r‖s bruta, um blob de 3 bytes e uma assinatura válida sobre outros dados deram GNUTLS_E_PK_SIG_VERIFY_FAILED (-89). Use o conversor DER ⇄ bruto para descartar um problema de codificação.

O ECDSA fica limitado às curvas do NIST de P-224 a P-521 — gnutls_ecc_curve_get_id("SECP256K1") retornou 0, ou seja, curva desconhecida —, enquanto Ed25519 e Ed448 assinaram e verificaram. Os arquivos de cabeçalho declaram GNUTLS_PK_MLKEM768 e GNUTLS_PK_MLDSA65, mas este build não implementa nenhum dos dois: eles não aparecem em gnutls_pk_list(), a geração de chaves ML-DSA-65 falha com GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM, e os grupos TLS listados por gnutls-cli --list incluem X25519 e X448, mas nenhum híbrido com ML-KEM. Um código que compila com essas constantes ainda pode falhar em tempo de execução, então confira a lista disponível em tempo de execução. Inspecione os certificados gerados pelo certtool com o decodificador de certificados.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/gnutls/run.sh executou GnuTLS 3.8.13 na imagem de contêiner alpine:3.24.2 em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Codificação da assinatura ECDSA

    der

    gnutls_privkey_sign_data retorna ASN.1 DER.

    Registrado pela verificação
    fact ecdsa-signature-encoding = der
  • Nonce do ECDSA

    rfc6979-opt-in

    Aleatório por padrão; GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE gerou assinaturas idênticas e reproduziu o apêndice A.2.5 da RFC 6979.

    Registrado pela verificação
    fact ecdsa-nonce = rfc6979-opt-in
    evidence ecdsa-nonce: default repeats: no; GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE repeats: yes and reproduces the RFC 6979 A.2.5 r: yes
  • Low-S ao assinar

    either

    O s não é normalizado: valores high-S apareceram entre 64 assinaturas.

    Registrado pela verificação
    fact ecdsa-low-s-sign = either
  • High-S ao verificar

    accepts-high-s

    Uma assinatura DER com s substituído por n − s foi verificada.

    Registrado pela verificação
    fact ecdsa-low-s-verify = accepts-high-s
  • Entrada do hash na chamada de assinatura

    hashes-message-or-digest

    gnutls_privkey_sign_data calcula o hash; gnutls_privkey_sign_hash2 assina um digest, e essa assinatura foi verificada contra a mensagem.

    Registrado pela verificação
    fact ecdsa-prehash = hashes-message-or-digest
  • Assinatura ECDSA malformada

    returns-false

    Uma assinatura r‖s bruta, um blob de 3 bytes e uma assinatura válida sobre outros dados retornaram, todos, GNUTLS_E_PK_SIG_VERIFY_FAILED (-89).

    Registrado pela verificação
    fact ecdsa-malformed-signature = returns-false
    evidence ecdsa-malformed-signature: gnutls_pubkey_verify_data2: raw r||s -89 (GNUTLS_E_PK_SIG_VERIFY_FAILED), 3 bytes -89 (GNUTLS_E_PK_SIG_VERIFY_FAILED), wrong message -89 (GNUTLS_E_PK_SIG_VERIFY_FAILED)
  • Curvas ECDSA

    P-224P-256P-384P-521

    P-224, P-256, P-384 e P-521; SECP256K1 não é uma curva conhecida.

    Registrado pela verificação
    fact ecdsa-curves = P-224, P-256, P-384, P-521
    evidence ecdsa-curves: gnutls_ecc_curve_get_id("SECP256K1") = 0 (0 = unknown)
  • EdDSA

    Ed25519Ed448

    Geração de chaves, assinatura e verificação funcionaram com Ed25519 e Ed448.

    Registrado pela verificação
    fact eddsa = Ed25519, Ed448
    evidence eddsa: Ed25519: keygen GNUTLS_E_SUCCESS, sign ok, verify ok
    evidence eddsa: Ed448: keygen GNUTLS_E_SUCCESS, sign ok, verify ok
  • Algoritmos pós-quânticos

    none

    ML-DSA e ML-KEM estão declarados nos arquivos de cabeçalho, mas ausentes de gnutls_pk_list(); a geração de chaves ML-DSA-65 falhou, e X25519-MLKEM768 é um grupo desconhecido.

    Registrado pela verificação
    fact pqc = none
    evidence pqc: the headers declare GNUTLS_PK_MLKEM768 = 14 and GNUTLS_PK_MLDSA65 = 16; gnutls_pk_list(): RSA, RSA-PSS, RSA-OAEP, RSA, DSA, GOST R 34.10-2012-512, GOST R 34.10-2012-256, GOST R 34.10-2001, EC/ECDSA, EdDSA (Ed25519), EdDSA (Ed448), DH, ECDH (X25519), ECDH (X448)
    evidence pqc: ML-DSA-65: in gnutls_pk_list: no; key generation GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM, sign and verify failed
    evidence pqc: ML-KEM-768: in gnutls_pk_list: no; gnutls_group_get_id("X25519-MLKEM768") = 0 (0 = unknown)
    evidence pqc: gnutls-cli --list Groups: GROUP-SECP192R1, GROUP-SECP224R1, GROUP-SECP256R1, GROUP-SECP384R1, GROUP-SECP521R1, GROUP-X25519, GROUP-GC256B, GROUP-GC512A, GROUP-X448, GROUP-FFDHE2048, GROUP-FFDHE3072, GROUP-FFDHE4096, GROUP-FFDHE6144, GROUP-FFDHE8192
    evidence pqc: shared libraries the gnutls package depends on: libbrotlidec.so.1 libbrotlienc.so.1 libc.musl-aarch64.so.1 libgmp.so.10 libhogweed.so.6 libidn2.so.0 libnettle.so.8 libp11-kit.so.0 libtasn1.so.6 libunistring.so.5 libz.so.1 libzstd.so.1 (GnuTLS 3.8.10 NEWS: PQC is only provided through leancrypto)

Uso

Gere uma chave P-256, assine duas vezes com a flag de reprodutibilidade e verifique, conferindo se as assinaturas são idênticas.
#include <gnutls/abstract.h>
#include <gnutls/gnutls.h>
#include <stdio.h>
#include <string.h>

int main(void) {
    gnutls_global_init();
    gnutls_privkey_t priv;
    gnutls_pubkey_t pub;
    gnutls_privkey_init(&priv);
    gnutls_privkey_generate(priv, GNUTLS_PK_ECDSA, GNUTLS_CURVE_TO_BITS(GNUTLS_ECC_CURVE_SECP256R1), 0);
    gnutls_pubkey_init(&pub);
    gnutls_pubkey_import_privkey(pub, priv, 0, 0);

    gnutls_datum_t msg = {(unsigned char *)"order #1042 approved", 20}, sig1, sig2;
    /* REPRODUCIBLE switches ECDSA to RFC 6979 nonces; the default is random. */
    gnutls_privkey_sign_data(priv, GNUTLS_DIG_SHA256, GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE, &msg, &sig1);
    gnutls_privkey_sign_data(priv, GNUTLS_DIG_SHA256, GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE, &msg, &sig2);

    /* Negative return codes mean failure; any malformed input is GNUTLS_E_PK_SIG_VERIFY_FAILED. */
    int rc = gnutls_pubkey_verify_data2(pub, GNUTLS_SIGN_ECDSA_SHA256, 0, &msg, &sig1);
    printf("verified: %d, deterministic: %d\n", rc >= 0, sig1.size == sig2.size && memcmp(sig1.data, sig2.data, sig1.size) == 0);
    gnutls_global_deinit();
    return 0;
}

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner alpine:3.24.2, e a execução falha se a saída não corresponder.

Configuração
apk add --no-cache -q build-base gnutls-dev=3.8.13-r0 >/dev/null
Comando
cc -o usage usage.c -lgnutls && ./usage
A saída deve corresponder a (expressão regular)
verified: 1, deterministic: 1

Bibliotecas