24 функции · JWT/JWS + JWKS · MIT

Справочник функций xjwt

Подпись и проверка JSON Web Token (RFC 7519) / JWS (RFC 7515): build.bat xjwt включает библиотеку. HS256/384/512 (HMAC), RS256/384/512 (RSA PKCS#1; ключи PKCS#8/PKCS#1), ES256 (ECDSA P-256, DER-подписи по RFC 7518 §3.4, двусторонняя совместимость с OpenSSL) и выбор ключей JWKS (RFC 7517). Claims передаются как xvalue* из xrt — нулевая мостовая прослойка на уровне скриптов.

Подпись (9 функций)

xjwtSign config-стиль

Подпись с полным контролем: инъекция iss/aud/sub/jti/exp/iat и kid в заголовок (iat всегда). Заголовок строится JSON-сериализацией (kid экранируется автоматически, без ограничения длины); ёмкость выходного буфера подписи проверяется (покрывает RSA-8192). Внимание: объект claims изменяется на месте.

char* xjwtSign(const xjwtconfig* pConfig, xvalue* claims);
Пример · выпуск access-токена
xjwtconfig cfg;
xjwtConfigInit(&cfg);
cfg.Alg = XJWT_ALG_RS256;
cfg.KeyPem = sPrivateKeyPem;   /* загружен при старте */
cfg.KeyId = "web-2026-09";
cfg.Issuer = "https://myapp.example.com";
cfg.Audience = "myapp-web";
cfg.ExpireSeconds = 900;

xvalue* claims = xrtValueObject();
xrtValueObjectSetNew(claims, xrtStrView("scope"),
    xrtValueString(xrtStrView("profile orders")));
char* sToken = xjwtSign(&cfg, claims);  /* освободить xrtFree */
xrtValueRelease(claims);

xjwtHs256 / Hs384 / Hs512 / Rs256 / Rs384 / Rs512 / Es256 одношаговые

Семь одношаговых подписей (claims + ключ + срок в секундах). Это семейство не инъектирует iss/aud — если проверяющая сторона в xjwtcheck указала Issuer/Audience, используйте xjwtSign. HS принимает ключ как C-строку (встроенный '\0' обрезает; бинарные ключи не поддерживаются); RS — PEM закрытого ключа PKCS#8/PKCS#1; ES256 — PEM закрытого ключа SEC1/PKCS#8.

char* xjwtHs256(xvalue* claims, const char* secret, int expireSeconds);

xjwtConfigInit инициализация

Обнуляет конфигурацию, по умолчанию HS256. KeyId длиной ≥ 256 символов отклоняется при подписи (симметрично лимиту проверяющей стороны).

Проверка (4 функции)

xjwtVerify путь PEM

Проверка за один шаг: декодирование alg из заголовка → проверка claims (нецелые exp/nbf отклоняются; iss/aud за константное время; aud принимает строки и массивы) → проверка подписи. HS принимает строку-ключ, RS/ES — PEM открытого ключа; тип ключа сверяется с семейством алгоритмов (защита от подмены). Успех — claims (освободить xrtValueRelease), неудача — NULL с кодом ошибки.

xvalue* xjwtVerify(const char* token, const char* keyPem, const xjwtcheck* check);
Пример · middleware аутентификации
xjwtcheck check;
xjwtCheckInit(&check);
check.Issuer = "https://myapp.example.com";
check.Audience = "myapp-web";
check.ClockLeeway = 30;

xvalue* claims = xjwtVerify(sBearerToken, sPublicKeyPem, &check);
if ( claims == NULL ) {
    if ( xjwtLastError() == XJWT_ERROR_EXPIRED )
        return 401;   /* истёк */
    return 401;           /* подделка / подмена / неверная подпись */
}
char aUser[64];
xjwtClaimString(claims, "sub", aUser, sizeof(aUser));
xrtValueRelease(claims);

xjwtKeyParse / xjwtKeyFree / xjwtVerifyKey кэш ключа

Высокочастотная проверка: открытый ключ разбирается один раз (RSA SPKI/PKCS#1 или EC P-256 SPKI; закрытые ключи и сертификаты отклоняются); объект кэша только для чтения и разделяем между потоками. VerifyKey отклоняет семейство HS и сверяет семейство алгоритмов с типом ключа. Кучный указатель — естественный путь для уровня скриптов.

xjwtkey* xjwtKeyParse(const char* publicPem); void xjwtKeyFree(xjwtkey* key); xvalue* xjwtVerifyKey(const char* token, const xjwtkey* key, const xjwtcheck* check);

JWKS (3 функции)

xjwtJwksParse / xjwtJwksFree набор ключей

Разбор JWKS (RFC 7517) JSON: RSA n/e и EC x/y (только P-256; прочие кривые пропускаются; координаты строго 32 байта). Не более 16 ключей — при превышении весь набор отклоняется; повреждённые записи (например, n без e) немедленно освобождаются.

xjwtjwks* xjwtJwksParse(const char* json); void xjwtJwksFree(xjwtjwks* jwks);

xjwtVerifyJwks проверка с выбором ключа

Выбор ключа по строгому совпадению kid из заголовка токена (без kid — первый ключ; kid ≥ 260 отклоняется везде). Явно отклоняет семейство HS; перекрёстные проверки RS* ↔ RSA и ES256 ↔ EC. Повтор при ротации: при xjwtLastError() == XJWT_ERROR_KEY_NOT_FOUND перезагрузите JWKS и проверьте ещё раз.

xvalue* xjwtVerifyJwks(const char* token, const xjwtjwks* jwks, const xjwtcheck* check);

Claims и ошибки (3 функции)

xjwtClaimsValid ручной поток

Автономная проверка claims (exp/nbf/iss/aud): требуется JSON-объект; exp/nbf нецелого типа всегда отклоняются; aud принимает строки и массивы (любое совпадение).

xjwtClaimString извлечение

Безопасное извлечение строкового claim: усечение до cap-1 с завершающим нулём; false, если claim отсутствует или не строка.

bool xjwtClaimString(const xvalue* claims, const char* key, char* pOut, size_t iCap);

xjwtLastError чтение ошибки

Возвращает код ошибки домена xjwt (XJWT_ERROR_*) текущего контекста выполнения, 0 — если текущая ошибка из другого домена. Читайте сразу после сбоя.

Декодирование и утилиты (5 функций)

xjwtDecode / xjwtDecodeHeader декодирование

Декодирование без проверки подписи (доверенные источники / отладка): первый возвращает claims и может отдать alg заголовка; второй возвращает объект заголовка с alg + kid (kid — кучная копия, освободить xrtFree). Claims/заголовок обязаны быть JSON-объектами; при переданном pKid kid ≥ 260 отклоняет вызов целиком.

xjwtCheckInit / xjwtAlgName / xjwtAlgParse утилиты

Обнуляет структуру проверки (NowOverride внедряет тестовые часы, ClockLeeway — допуск в секундах); преобразует enum алгоритма в имя и обратно.

void xjwtCheckInit(xjwtcheck* pCheck); const char* xjwtAlgName(int alg); int xjwtAlgParse(const char* name);
Базовая безопасность: нецелые exp/nbf отклоняются, alg=none и подмена алгоритма блокируются на всех путях (включая JWKS), iss/aud/HS за константное время, строгое сопоставление kid с трёхуровневой длиной. 117 тестов (двусторонняя совместимость с OpenSSL, RSA-8192, fuzz 2000 случаев, замер нулевых утечек). Полный исходник — lib/xjwt; сопрягается на данных с xoauth2 для OIDC-логина.