Цепочки доверия и сертификаты на основе Ed25519

Алгоритм Ed25519 относится к семейству схем цифровой подписи на основе эллиптических кривых (EdDSA). В экосистеме TweetNaCl.js он реализован как основной механизм асимметричной аутентификации данных, обеспечивающий высокую скорость, компактные ключи и устойчивость к целому классу криптоаналитических атак.

Ключевая особенность Ed25519 заключается в том, что он не предназначен для шифрования данных. Его задача — подтверждение целостности и подлинности сообщений через цифровую подпись. В связке с моделью доверия это становится фундаментом для построения цепочек сертификатов.

В криптографическом смысле доверие не передаётся «магически». Оно строится через проверяемые утверждения:

  • определённый субъект владеет приватным ключом
  • этот субъект может подписывать данные
  • подпись проверяется публичным ключом
  • публичный ключ сам может быть заверен другим ключом

Именно эта рекурсивная структура приводит к модели цепочек доверия.


Базовые операции TweetNaCl.js для Ed25519

Библиотека TweetNaCl.js предоставляет минималистичный интерфейс для работы с Ed25519:

  • генерация ключевой пары
  • создание подписи
  • проверка подписи

Типовой набор операций выглядит следующим образом:

const nacl = require('tweetnacl');
const util = require('tweetnacl-util');

// генерация ключей
const keyPair = nacl.sign.keyPair();

// сообщение
const message = util.decodeUTF8("critical data");

// подпись
const signature = nacl.sign.detached(message, keyPair.secretKey);

// проверка подписи
const isValid = nacl.sign.detached.verify(
  message,
  signature,
  keyPair.publicKey
);

Важно учитывать, что secretKey в Ed25519 включает в себя как приватную, так и публичную часть, тогда как publicKey используется отдельно.


Почему в NaCl нет сертификатов

TweetNaCl.js реализует криптографический примитивный слой. Он не включает инфраструктуру:

  • X.509
  • ASN.1
  • PKI (Public Key Infrastructure)
  • CRL/OCSP

Это сознательное решение: библиотека ограничивается криптографией, оставляя протокольную и инфраструктурную часть разработчику.

Поэтому сертификаты и цепочки доверия строятся поверх Ed25519 вручную.


Концепция сертификата поверх Ed25519

Сертификат в контексте NaCl-подобных систем представляет собой структуру данных, содержащую:

  • публичный ключ субъекта
  • идентификатор субъекта
  • метаданные (роль, срок действия, права)
  • подпись издателя сертификата

Пример структуры:

{
  "subject": "device-42",
  "publicKey": "BASE64_PUBLIC_KEY",
  "issuedAt": 1710000000,
  "expiresAt": 1740000000,
  "issuer": "ca-root",
  "signature": "BASE64_SIGNATURE"
}

Подпись формируется не на JSON-строку как таковую, а на каноническое представление данных.


Канонизация данных перед подписью

Одна из ключевых проблем любых криптографических систем поверх JSON — неоднозначность сериализации.

Разные сериализации одного и того же объекта могут давать разные байтовые представления, что ломает проверку подписи.

Поэтому вводится правило канонизации:

  • фиксированный порядок ключей
  • отсутствие пробелов
  • единый формат чисел
  • строгая UTF-8 кодировка

Простейшая стратегия:

function canonicalize(obj) {
  return JSON.stringify(obj, Object.keys(obj).sort());
}

Далее результат переводится в Uint8Array:

const message = util.decodeUTF8(canonicalize(certData));

Формирование сертификата

Процесс выпуска сертификата включает следующие шаги:

  1. формирование структуры без подписи
  2. сериализация в канонический формат
  3. подпись приватным ключом издателя
  4. добавление подписи в структуру
function signCertificate(cert, issuerSecretKey) {
  const dataToSign = {
    subject: cert.subject,
    publicKey: cert.publicKey,
    issuedAt: cert.issuedAt,
    expiresAt: cert.expiresAt,
    issuer: cert.issuer
  };

  const message = util.decodeUTF8(canonicalize(dataToSign));

  const signature = nacl.sign.detached(message, issuerSecretKey);

  return {
    ...dataToSign,
    signature: util.encodeBase64(signature)
  };
}

Проверка сертификата

Проверка включает несколько этапов:

  • проверка подписи
  • проверка срока действия
  • проверка цепочки доверия
function verifyCertificate(cert, issuerPublicKey) {
  const dataToVerify = {
    subject: cert.subject,
    publicKey: cert.publicKey,
    issuedAt: cert.issuedAt,
    expiresAt: cert.expiresAt,
    issuer: cert.issuer
  };

  const message = util.decodeUTF8(canonicalize(dataToVerify));
  const signature = util.decodeBase64(cert.signature);

  const signatureValid = nacl.sign.detached.verify(
    message,
    signature,
    issuerPublicKey
  );

  const now = Math.floor(Date.now() / 1000);
  const timeValid = now >= cert.issuedAt && now <= cert.expiresAt;

  return signatureValid && timeValid;
}

Цепочка доверия

Цепочка доверия строится через рекурсивную верификацию сертификатов:

  • root CA (корневой сертификат)
  • intermediate CA (промежуточные центры)
  • leaf certificate (конечный субъект)

Каждый уровень подписывает следующий.


Модель корневого доверия

Корневой ключ считается доверенным по определению системы. Его публичный ключ встраивается в приложение или распространяется через защищённый канал.

const rootCA = {
  publicKey: util.decodeBase64(ROOT_PUBLIC_KEY),
  name: "root-ca"
};

Корневой CA подписывает промежуточные сертификаты:

  • intermediate CA получает подпись root CA
  • leaf получает подпись intermediate CA

Проверка цепочки сертификатов

Алгоритм проверки строится от листа к корню:

  1. проверить leaf сертификат через intermediate public key
  2. проверить intermediate через root public key
  3. убедиться, что root доверенный
function verifyChain(leafCert, intermediateCert, rootCA) {

  const leafValid = verifyCertificate(
    leafCert,
    util.decodeBase64(intermediateCert.publicKey)
  );

  const intermediateValid = verifyCertificate(
    intermediateCert,
    rootCA.publicKey
  );

  return leafValid && intermediateValid;
}

Делегирование доверия

Цепочки позволяют строить системы делегирования:

  • root CA не подписывает конечные устройства
  • intermediate CA ограничены по домену доверия
  • leaf сертификаты применяются в реальных операциях

Пример ограничений в метаданных:

{
  "permissions": ["sign:messages", "auth:device"],
  "scope": "iot-network"
}

Эти поля также включаются в подписываемую часть сертификата.


Встраивание сертификатов в протоколы

В реальных системах сертификаты на Ed25519 используются в:

  • аутентификации устройств IoT
  • защищённых API-запросах
  • peer-to-peer сетях
  • распределённых системах идентификации

Типичный сценарий:

  1. устройство отправляет сертификат
  2. сервер проверяет цепочку
  3. сервер проверяет подпись запроса тем же ключом
  4. доступ предоставляется при успешной верификации

Подпись запросов на основе сертификата

Сертификат даёт не только идентичность, но и возможность подписывать сообщения:

const message = util.decodeUTF8("request-data");

const signature = nacl.sign.detached(
  message,
  deviceSecretKey
);

Сервер проверяет:

  • валидность сертификата устройства
  • соответствие публичного ключа
  • подпись сообщения

Ротация ключей и обновление цепочек

Ключевая проблема долгоживущих систем — обновление ключей.

Подходы:

  • выпуск нового сертификата с новым ключом
  • перекрёстная подпись старого и нового ключей
  • ограниченный срок действия сертификатов

Сценарий миграции:

  • старый сертификат подписывает новый
  • новый получает подпись от CA
  • оба валидны в переходный период

Отзыв сертификатов

В NaCl нет встроенного механизма отзыва, поэтому он реализуется отдельно:

  • список отозванных сертификатов (CRL-подобная структура)
  • централизованный реестр
  • распределённый gossip-список

Пример структуры:

{
  "revoked": [
    "device-42",
    "device-99"
  ]
}

При проверке сертификата выполняется дополнительная проверка идентификатора.


Типичные ошибки реализации

В системах на основе TweetNaCl.js часто возникают ошибки:

  • отсутствие канонизации JSON
  • использование нестабильной сериализации
  • повторное использование nonce в других схемах (не относится напрямую к Ed25519, но встречается рядом)
  • доверие к неподписанным intermediate сертификатам
  • игнорирование срока действия

Безопасная модель хранения ключей

Приватные ключи Ed25519 требуют строгого обращения:

  • хранение в защищённом хранилище (HSM, secure enclave)
  • отсутствие логирования ключевых материалов
  • разделение ключей подписи и идентификации
  • минимизация времени жизни секретных ключей

Архитектура доверенной системы на NaCl

Типовая схема включает:

  • root CA (офлайн)
  • intermediate CA (онлайн, ограниченный)
  • устройство/клиент (leaf)
  • сервер верификации

Поток доверия:

  • root подписывает intermediate
  • intermediate подписывает устройства
  • устройства подписывают запросы
  • сервер проверяет цепочку и подпись

Связь Ed25519 и доверия в распределённых системах

Ed25519 обеспечивает криптографическую основу, но не определяет:

  • кому доверять
  • как распространять ключи
  • как обновлять доверие
  • как отзывать доступ

Эти аспекты формируют отдельный уровень — протокольную инфраструктуру поверх TweetNaCl.js, где сертификаты и цепочки доверия становятся основным механизмом управления идентичностью.