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

GnuTLS

GnuTLS — библиотека TLS и X.509 проекта GNU: ECDSA с подписями DER на кривых NIST, RFC 6979 по флагу, Ed25519 и Ed448, а в проверенной сборке дистрибутива нет ни secp256k1, ни работающих постквантовых алгоритмов.
Лицензия
LGPL-2.1-or-later
Проверенная версия
3.8.13 ·
Исходный код
gitlab.com/gnutls/gnutls
Документация
www.gnutls.org/manual/

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

ECDSAEdDSA

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

GnuTLS обеспечивает работу с TLS, X.509 и PKCS для многих компонентов GNU и Linux и поставляется с утилитами certtool и gnutls-cli. Абстрактные интерфейсы gnutls_privkey_* и gnutls_pubkey_* одинаково работают с программными ключами, токенами PKCS#11 и TPM. Факты на этой странице проверены на пакете Alpine 3.24.2 с GnuTLS 3.8.13, которая использует Nettle для арифметики. Начиная с GnuTLS 3.8.10 постквантовые алгоритмы берутся только из необязательной библиотеки leancrypto, а этот пакет с ней не скомпонован.

gnutls_privkey_sign_data возвращает подписи ECDSA в DER со случайным nonce; флаг GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE переключает подпись на RFC 6979, и с ним тестовый вектор для P-256 из RFC воспроизвёлся точно. Значение s не нормализуется, а подписи с high-S проходят проверку. gnutls_privkey_sign_hash2 подписывает дайджест, который вы вычислили сами.

При неудачной проверке функции возвращают отрицательный код ошибки, и все виды неудач выглядели одинаково: для подписи raw r‖s, 3-байтового фрагмента данных и верной подписи других данных результат был один — GNUTLS_E_PK_SIG_VERIFY_FAILED (-89). Чтобы исключить проблему с кодированием, воспользуйтесь конвертером DER ⇄ raw.

ECDSA ограничен кривыми NIST от P-224 до P-521: gnutls_ecc_curve_get_id("SECP256K1") вернула 0, то есть кривая неизвестна. При этом Ed25519 и Ed448 работают и для подписи, и для проверки. В заголовочных файлах объявлены GNUTLS_PK_MLKEM768 и GNUTLS_PK_MLDSA65, но эта сборка не реализует ни один из них: их нет в gnutls_pk_list(), генерация ключа ML-DSA-65 завершается ошибкой GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM, а среди групп TLS, которые выводит gnutls-cli --list, есть X25519 и X448, но нет ни одной гибридной группы с ML-KEM. Код, который компилируется с этими константами, всё равно может завершиться ошибкой во время выполнения, поэтому проверяйте фактический список алгоритмов в среде выполнения. Сертификаты, созданные certtool, разбирайте в декодере сертификатов.

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

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

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

    der

    gnutls_privkey_sign_data возвращает ASN.1 DER.

    Что записала проверка
    fact ecdsa-signature-encoding = der
  • Nonce в ECDSA

    rfc6979-opt-in

    По умолчанию nonce случайный; с GNUTLS_PRIVKEY_FLAG_REPRODUCIBLE подписи совпали, а тестовый вектор из приложения A.2.5 RFC 6979 воспроизвёлся.

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

    either

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

    Что записала проверка
    fact ecdsa-low-s-sign = either
  • High-S при проверке

    accepts-high-s

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

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

    hashes-message-or-digest

    gnutls_privkey_sign_data хеширует данные; gnutls_privkey_sign_hash2 подписывает дайджест, и такая подпись прошла проверку по исходному сообщению.

    Что записала проверка
    fact ecdsa-prehash = hashes-message-or-digest
  • Некорректная подпись ECDSA

    returns-false

    Для подписи raw r‖s, 3-байтового фрагмента данных и верной подписи других данных функция одинаково вернула GNUTLS_E_PK_SIG_VERIFY_FAILED (-89).

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

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

    P-224, P-256, P-384 и P-521; кривая SECP256K1 неизвестна.

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

    Генерация ключей, подпись и проверка работают для Ed25519 и Ed448.

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

    none

    ML-DSA и ML-KEM объявлены в заголовочных файлах, но отсутствуют в gnutls_pk_list(); генерация ключа ML-DSA-65 завершилась ошибкой, а X25519-MLKEM768 — неизвестная группа.

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

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

Сгенерируйте ключ P-256, дважды подпишите с флагом воспроизводимости, проверьте подписи и убедитесь, что они совпадают.
#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;
}

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

Подготовка
apk add --no-cache -q build-base gnutls-dev=3.8.13-r0 >/dev/null
Команда
cc -o usage usage.c -lgnutls && ./usage
Вывод должен совпадать (регулярное выражение)
verified: 1, deterministic: 1

Библиотеки