# PKI Aura Aura использует небольшую самодостаточную X.509-PKI для **взаимной аутентификации** во внутреннем рукопожатии. Один самоподписанный **CA** Aura выдаёт один сертификат для **сервера** и по одному сертификату для каждого **клиента**. Во время рукопожатия клиент проверяет сертификат сервера, а сервер — сертификат клиента, и в обе стороны проверка идёт против этого CA. PKI реализована в крейте `aura-pki` (`ca.rs`, `cert.rs`, `store.rs`) и доступна в командной строке как `aura pki ...` (`crates/aura-cli/src/pki.rs`, `crates/aura-cli/src/main.rs`). > Внешний QUIC/TLS-слой эту PKI **не** использует — он принимает любой сертификат (см. > `protocol.md`, раздел про слой мимикрии). Всё доверие сертификатам сосредоточено во внутреннем > рукопожатии Aura. --- ## Модель доверия ``` Aura CA (self-signed) CN = , isCA, keyCertSign/crlSign | +------------+------------+ | | server leaf client leaf(s) CN = CN = SAN: DNS: (нет SAN) EKU: serverAuth EKU: clientAuth ``` - **CA** самоподписан, имеет `BasicConstraints: CA` (unconstrained) и `keyUsage`: `keyCertSign` + `crlSign` + `digitalSignature`. Срок действия по умолчанию — **3650 дней**. - **Server leaf** несёт `CN = `, **`DNS:` SAN** и `extendedKeyUsage = serverAuth`. Именно DNS-SAN сравнивается клиентом с ожидаемым `server_name`. - **Client leaf** несёт `CN = ` и `extendedKeyUsage = clientAuth`. Этот CN — та идентичность, которую увидит сервер и запишет как `peer_id` сессии. - `keyUsage` для листовых сертификатов: `digitalSignature` + `keyEncipherment`. Срок действия по умолчанию — **365 дней**. - У всех выпускаемых сертификатов (и у CA, и у листовых) `not_before` смещён назад на **5 минут**, чтобы выдерживать небольшой расхождение часов. ### Алгоритмы Все ключи — **ECDSA P-256 / SHA-256** (`KeyPair::generate` rcgen по умолчанию). Приватные ключи сохраняются в **PKCS#8 PEM**. Проверка цепочки (`cert.rs`) принимает ECDSA P-256/SHA-256 (обязательно), а также ECDSA P-384/SHA-384 и Ed25519, — так что развёртывание сможет позже сменить тип ключа без изменения кода. --- ## Раскладка файлов CLI хранит файлы в обычных директориях. Стандартные имена (`crates/aura-cli/src/pki.rs`): | Файл | Константа | Содержимое | |---------------|------------|--------------------------------------------------| | `ca.crt` | `CA_CERT` | Сертификат CA (PEM) | | `ca.key` | `CA_KEY` | Приватный ключ CA (PKCS#8 PEM) — **секрет** | | `server.crt` | | Листовой сертификат сервера (PEM) | | `server.key` | | Приватный ключ сервера (PEM) — **секрет** | | `client.crt` | | Листовой сертификат клиента (PEM) | | `client.key` | | Приватный ключ клиента (PEM) — **секрет** | | `revoked.crl` | `CRL_FILE` | Список отозванных идентификаторов (по одному в строке) | Команды `issue-server` и `issue-client` загружают CA из `ca.crt` + `ca.key` в директории CA и записывают `server.{crt,key}` / `client.{crt,key}` в выходную директорию. Пути, начинающиеся с `~`, раскрываются в домашнюю директорию (из `$HOME`, либо `$USERPROFILE` на Windows). Эти имена напрямую соответствуют секции `[pki]` в `server.toml` / `client.toml` (`ca_cert`, `cert`, `key`). --- ## Команды `aura pki` ``` aura pki init --ca-name --out aura pki issue-server --domain --out [--ca ] aura pki issue-client --id --out [--ca ] aura pki revoke --id [--crl ] aura pki list [--crl ] ``` Для `issue-server` / `issue-client` параметр `--ca` по умолчанию равен значению `--out` (так что CA и выпущенный лист могут лежать в одной директории). Для `revoke` / `list` параметр `--crl` по умолчанию равен `./revoked.crl`. ### `init` — создать CA Генерирует свежий самоподписанный CA и записывает `ca.crt` + `ca.key` в `--out` (директория создаётся при необходимости). ```bash aura pki init --ca-name "Aura Root CA" --out ~/.aura # CA generated: # cert: ~/.aura/ca.crt # key: ~/.aura/ca.key ``` ### `issue-server` — выпустить сертификат сервера Выпускает листовой сертификат для DNS-имени, подписанный CA, с SAN `DNS:` и EKU `serverAuth`. ```bash aura pki issue-server --domain vpn.example.com --out ~/.aura --ca ~/.aura # server certificate issued for 'vpn.example.com': # cert: ~/.aura/server.crt # key: ~/.aura/server.key ``` > Значение `--domain` должно совпадать с тем именем, которое клиент ожидает в рукопожатии. В > поставляемой конфигурации клиента это имя берётся из `[client] sni`, поэтому SNI камуфляжа и > проверяемый SAN сервера — это одно и то же значение. ### `issue-client` — выпустить сертификат клиента Выпускает листовой сертификат с `CN = ` и EKU `clientAuth`. Это `` станет проверенным `peer_id`, который увидит сервер. ```bash aura pki issue-client --id laptop --out ~/.aura --ca ~/.aura # client certificate issued for 'laptop': # cert: ~/.aura/client.crt # key: ~/.aura/client.key ``` ### `revoke` — добавить в список отзыва Добавляет идентификатор — это либо **client id / Common Name**, либо **серийный номер сертификата** (строчные шестнадцатеричные цифры без разделителей) — в CRL-файл, создавая его (и родительские директории) при отсутствии. ```bash aura pki revoke --id laptop --crl ~/.aura/revoked.crl # revoked 'laptop' (CRL: ~/.aura/revoked.crl) ``` ### `list` — показать отозванные идентификаторы Печатает идентификаторы из CRL-файла (пусто, если файла нет). ```bash aura pki list --crl ~/.aura/revoked.crl # revoked identifiers (CRL: ~/.aura/revoked.crl): # laptop ``` ### Полный пример ```bash # 1. Создать CA. aura pki init --ca-name "Aura Root CA" --out ~/.aura # 2. Выпустить серверный сертификат для публичного DNS-имени. aura pki issue-server --domain vpn.example.com --out ~/.aura # 3. Выпустить клиентский сертификат — по одному на устройство. aura pki issue-client --id laptop --out ~/.aura # 4. (позже) Отозвать скомпрометированный клиент. aura pki revoke --id laptop ``` --- ## Проверка Проверку выполняет `AuraCertVerifier` (`crates/aura-pki/src/cert.rs`), собранный из PEM-сертификата CA. Внутри он использует **`rustls-webpki`** для валидации листового сертификата пира против CA как trust anchor. Рукопожатие Aura вызывает его с обеих сторон (см. `protocol.md`). **Сертификат сервера** (`verify_server_cert`), запускает клиент: 1. webpki-валидация цепочки против CA с key usage **`serverAuth`** плюс проверка срока действия (времени). 2. Лист должен быть валиден для запрошенного `server_name` (совпадение DNS-SAN); расхождение — `NameMismatch`. 3. Проверка по CRL (см. ниже). **Сертификат клиента** (`verify_client_cert`), запускает сервер: 1. webpki-валидация цепочки против CA с key usage **`clientAuth`** плюс проверка срока действия. 2. **client id** извлекается как первый Common Name из subject листа (отсутствие CN — `MissingIdentity`). 3. Проверка по CRL. 4. Возвращает client id, который рукопожатие фиксирует как `peer_id` сессии. Листовой сертификат передаётся **inline** в рукопожатии (DER, без промежуточной цепочки); CA — это единственный trust anchor. Владение приватным ключом листового сертификата доказывается отдельно подписью рукопожатия по транскрипту (см. `protocol.md`). Ошибки сообщаются как `PkiError`: `CertParse`, `EmptyChain`, `TrustAnchor`, `Verification`, `NameMismatch`, `MissingIdentity`, `Revoked`. --- ## Отзыв (CRL) Механизм отзыва в Aura v1 намеренно минимальный (`crates/aura-pki/src/store.rs`). `CrlStore` — это **множество строк-идентификаторов отозванных сертификатов**, где идентификатор — это либо: - **серийный номер** сертификата (строчные hex-цифры без разделителей), либо - **client id / Common Name**. При проверке, если CRL непуст, листовой сертификат отвергается (`Revoked`), когда **либо** его серийный номер, **либо** его Common Name присутствует в множестве. Пустой CRL пропускает проверку полностью. Формат на диске — один идентификатор в строке; пустые строки и комментарии `#` игнорируются при загрузке. Файл управляется командами `aura pki revoke` / `aura pki list`. > Ограничение v1: это плоское множество разрешения/запрета, а не подписанный X.509 CRL. Нет > подписи CRL, нет `nextUpdate` и нет автоматического распространения — файл нужно доставить на > проверяющую сторону вне протокола. Верификатор передаёт `None` в собственные крючки отзыва > webpki и полагается исключительно на это множество. --- ## Замечания по безопасности - **Защищайте приватные ключи.** `ca.key` — корень всего доверия; владея им, можно выпускать любые валидные серверные/клиентские сертификаты. `server.key` / `client.key` должны оставаться на своих хостах. CLI пишет их с дефолтными правами файловой системы — ограничивайте доступ средствами ОС. - **CA самоподписан и не ограничен** (`BasicConstraints: CA` unconstrained). Это единственный trust anchor; в v1 нет уровня промежуточных CA. - **Идентичность сервера связана с именем.** Клиент принимает только тот серверный лист, чей DNS-SAN совпадает с ожидаемым именем, поэтому другой валидный лист от того же CA не будет принят для чужого хоста. - **Отзыв — best-effort** (см. выше): планируйте раздачу CRL-файла и поддерживайте его в актуальном состоянии на каждом сервере, который проверяет клиентов. - **Срок жизни листов — 365 дней**; планируйте перевыпуск. Автоматической ротации в v1 нет.