Saltar al contenido
ecdsa.com
C · Línea de comandos

GnuTLS

GnuTLS, la biblioteca TLS y X.509 del proyecto GNU: ECDSA con DER en las curvas NIST, RFC 6979 mediante un indicador, Ed25519 y Ed448 y, en la compilación de distribución comprobada, ni secp256k1 ni algoritmos poscuánticos que funcionen.
Licencia
LGPL-2.1-or-later
Versión comprobada
3.8.13 ·
Código fuente
gitlab.com/gnutls/gnutls
Documentación
www.gnutls.org/manual/

Compatibilidad de un vistazo

ECDSAEdDSA

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

GnuTLS proporciona TLS, X.509 y manejo de PKCS a muchos componentes de GNU y Linux, e incluye certtool y gnutls-cli. Sus interfaces abstractas gnutls_privkey_* y gnutls_pubkey_* funcionan igual con claves de software, tokens PKCS#11 y TPM. Los datos de esta página se comprobaron con el paquete de Alpine 3.24.2, GnuTLS 3.8.13, que usa Nettle para la aritmética. Desde GnuTLS 3.8.10, los algoritmos poscuánticos solo llegan a través de la biblioteca opcional leancrypto, y este paquete no la enlaza.

gnutls_privkey_sign_data devuelve firmas ECDSA en DER con un nonce aleatorio; el indicador GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE cambia a RFC 6979, y con él el vector de prueba P-256 del RFC se reprodujo exactamente. s no se normaliza y las firmas high-S se verifican. gnutls_privkey_sign_hash2 firma un resumen que calculas tú.

La verificación devuelve un código de error negativo cuando falla, y todos los tipos de fallo tenían el mismo aspecto: una firma r‖s en bruto, un blob de 3 bytes y una firma válida sobre otros datos dieron todos GNUTLS_E_PK_SIG_VERIFY_FAILED (-89). Usa el conversor DER ⇄ en bruto para descartar un problema de codificación.

ECDSA se limita a las curvas NIST de P-224 a P-521 —gnutls_ecc_curve_get_id("SECP256K1") devolvió 0, desconocida—, mientras que tanto Ed25519 como Ed448 firmaron y verificaron. Los archivos de cabecera declaran GNUTLS_PK_MLKEM768 y GNUTLS_PK_MLDSA65, pero esta compilación no implementa ninguno de los dos: faltan en gnutls_pk_list(), la generación de claves ML-DSA-65 falla con GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM, y los grupos TLS que lista gnutls-cli --list incluyen X25519 y X448, pero ningún híbrido ML-KEM. El código que compila con estas constantes puede fallar igualmente en tiempo de ejecución, así que comprueba la lista que ofrece el entorno de ejecución. Inspecciona los certificados que produce certtool con el decodificador de certificados.

Datos y las comprobaciones que los respaldan

Nada de lo que sigue está copiado de la documentación. La comprobación content/libraries/verify/gnutls/run.sh ejecutó GnuTLS 3.8.13 en la imagen de contenedor alpine:3.24.2 el 20 de octubre de 2026; la página debe coincidir con lo que imprimió, y cada dato cita esas líneas.

  • Codificación de la firma ECDSA

    der

    gnutls_privkey_sign_data devuelve DER ASN.1.

    Registrado por la comprobación
    fact ecdsa-signature-encoding = der
  • Nonce de ECDSA

    rfc6979-opt-in

    Aleatorio por defecto; GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE dio firmas idénticas y reprodujo el apéndice A.2.5 del RFC 6979.

    Registrado por la comprobación
    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 al firmar

    either

    s no se normaliza: aparecieron valores high-S entre 64 firmas.

    Registrado por la comprobación
    fact ecdsa-low-s-sign = either
  • High-S al verificar

    accepts-high-s

    Se verificó una firma DER con s sustituido por n − s.

    Registrado por la comprobación
    fact ecdsa-low-s-verify = accepts-high-s
  • De qué calcula el hash la llamada de firma

    hashes-message-or-digest

    gnutls_privkey_sign_data calcula el hash; gnutls_privkey_sign_hash2 firma un resumen, y esa firma se verificó contra el mensaje.

    Registrado por la comprobación
    fact ecdsa-prehash = hashes-message-or-digest
  • Firma ECDSA mal formada

    returns-false

    Una firma r‖s en bruto, un blob de 3 bytes y una firma válida sobre otros datos devolvieron todos GNUTLS_E_PK_SIG_VERIFY_FAILED (-89).

    Registrado por la comprobación
    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 y P-521; SECP256K1 no es una curva conocida.

    Registrado por la comprobación
    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

    Se generaron claves Ed25519 y Ed448, y con ellas se firmó y se verificó.

    Registrado por la comprobación
    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 poscuánticos

    none

    ML-DSA y ML-KEM están declarados en los archivos de cabecera, pero no aparecen en gnutls_pk_list(); la generación de claves ML-DSA-65 falló, y X25519-MLKEM768 es un grupo desconocido.

    Registrado por la comprobación
    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

Genera una clave P-256, firma dos veces con el indicador reproducible, verifica y comprueba que las firmas son 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;
}

El arnés de pruebas de fragmentos de código ejecuta cada ejemplo tal cual en la imagen de contenedor alpine:3.24.2, y la ejecución falla si la salida no coincide.

Configuración
apk add --no-cache -q build-base gnutls-dev=3.8.13-r0 >/dev/null
Comando
cc -o usage usage.c -lgnutls && ./usage
La salida debe coincidir (expresión regular)
verified: 1, deterministic: 1

Bibliotecas