Расширение Authority Information Access (AIA)

В расширении Authority Information Access (AIA) сертификата X.509 содержится информация о том, где можно получить дополнительные данные, связанные с удостоверяющим центром (CA). Обычно это ссылки на:

  • OCSP-ресурс для проверки статуса сертификата
  • URL, по которому можно загрузить сертификат издателя (CA Issuers)

Структура AIA представляет собой набор AccessDescription, где каждый элемент описывает тип доступа и соответствующий URI.

На уровне ASN.1 это выглядит как последовательность:

  • accessMethod (OID)
  • accessLocation (GeneralName, чаще всего URI)

На практике наиболее часто встречаются два OID:

  • OCSP: 1.3.6.1.5.5.7.48.1
  • CA Issuers: 1.3.6.1.5.5.7.48.2

Работа с расширением AIA в Jsrsasign основана на разборе структуры сертификата X.509 и извлечении соответствующего расширения из списка extensions.

В библиотеке используется объект X509, который предоставляет методы для декодирования сертификата и доступа к его полям.

const certPEM = `-----BEGIN CERTIFICATE-----
MIID...
-----END CERTIFICATE-----`;

const x = new X509();
x.readCertPEM(certPEM);

После загрузки сертификата доступ к расширениям осуществляется через внутреннюю ASN.1 структуру:

const info = x.getInfo();
console.log(info);

Однако для работы именно с AIA требуется более низкоуровневый разбор через getExtInfo() или анализ расширений вручную.


Каждое расширение в X.509 представлено в виде структуры:

  • extnID
  • critical (boolean)
  • extnValue (DER-encoded data)

В Jsrsasign доступ к ним осуществляется следующим образом:

const exts = x.getExtInfo();
console.log(exts);

Внутри результата будет массив объектов, среди которых можно найти AIA по OID:

const AIA_OID = "1.3.6.1.5.5.7.1.1";

Структура Authority Information Access

После декодирования AIA содержит массив accessDescription:

AuthorityInfoAccessSyntax  ::=
        SEQUENCE SIZE (1..MAX) OF AccessDescription

AccessDescription  ::=  SEQUENCE {
        accessMethod          OBJECT IDENTIFIER,
        accessLocation        GeneralName  }

В Jsrsasign это обычно представлено как массив объектов:

[
  {
    accessMethod: "1.3.6.1.5.5.7.48.1",
    accessLocation: "http://ocsp.example.com"
  },
  {
    accessMethod: "1.3.6.1.5.5.7.48.2",
    accessLocation: "http://ca.example.com/issuer.crt"
  }
]

Разбор AIA из сертификата

Jsrsasign не всегда предоставляет прямой высокоуровневый API только для AIA, поэтому используется комбинированный подход через ASN.1 парсер:

const hex = x.hex;
const asn1 = ASN1HEX.getVbyList(
  hex,
  0,
  ["tbsCertificate", "extensions", "extnValue"],
  "30"
);

Далее выполняется декодирование структуры AIA:

const aiaAsn1 = ASN1HEX.parseHex(asn1);
console.log(aiaAsn1);

Определение OCSP endpoint

Для извлечения OCSP URL необходимо отфильтровать accessMethod:

const exts = x.getExtInfo();

let ocspURL = null;

exts.forEach(ext => {
  if (ext.extname === "authorityInfoAccess") {
    const aia = ext.value;

    aia.forEach(item => {
      if (item.accessMethod === "1.3.6.1.5.5.7.48.1") {
        ocspURL = item.accessLocation;
      }
    });
  }
});

console.log(ocspURL);

Извлечение CA Issuers

Аналогично OCSP, но используется другой OID:

const CA_ISSUERS_OID = "1.3.6.1.5.5.7.48.2";

let issuerURL = null;

exts.forEach(ext => {
  if (ext.extname === "authorityInfoAccess") {
    ext.value.forEach(item => {
      if (item.accessMethod === CA_ISSUERS_OID) {
        issuerURL = item.accessLocation;
      }
    });
  }
});

console.log(issuerURL);

Практическое значение AIA в проверке сертификатов

При построении цепочки доверия AIA используется для:

  • автоматической загрузки промежуточных сертификатов
  • проверки статуса через OCSP
  • ускорения валидации цепочек без локального хранилища CA

В сценариях TLS-клиентов AIA играет ключевую роль при отсутствии полного набора промежуточных сертификатов.


Работа с PEM и DER представлением

Jsrsasign поддерживает оба формата сертификатов. AIA извлекается одинаково после парсинга:

const x = new X509();
x.readCertPEM(pemString);

или

x.readCertHex(hexString);

После этого структура расширений остается одинаковой.


Низкоуровневый разбор через ASN.1 HEX API

Для более глубокого контроля используется ASN1HEX:

const aiaIdx = ASN1HEX.getIdxbyList(
  x.hex,
  0,
  ["tbsCertificate", "extensions"]
);

Затем выполняется итерация по расширениям:

const extSeq = ASN1HEX.getChildIdx(x.hex, aiaIdx);

extSeq.forEach(idx => {
  const oid = ASN1HEX.getVbyList(x.hex, idx, [0], "06");

  if (oid === "1.3.6.1.5.5.7.1.1") {
    const value = ASN1HEX.getVbyList(x.hex, idx, [1], "04");
    console.log(value);
  }
});

Особенности интерпретации URI

Значение accessLocation почти всегда представлено как GeneralName типа uniformResourceIdentifier:

  • HTTP URL для OCSP
  • HTTP/HTTPS URL для CA certificates

Иногда встречаются LDAP-ссылки в корпоративных PKI:

ldap://ca.example.com/cn=IntermediateCA,dc=example,dc=com

Обработка нескольких AIA записей

Расширение может содержать несколько записей, и порядок имеет значение:

  • первый OCSP endpoint считается основным
  • CA Issuers может содержать резервные источники

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

[
  { method: "OCSP", url: "http://ocsp1.example.com" },
  { method: "OCSP", url: "http://ocsp2.example.com" },
  { method: "CA_ISSUERS", url: "http://ca.example.com/1.crt" }
]

Интеграция AIA в проверку цепочек

В логике построения цепочки сертификатов AIA используется как fallback механизм:

  1. Проверка локального хранилища CA
  2. Если промежуточный сертификат отсутствует
  3. Использование CA Issuers URL из AIA
  4. Загрузка и повторная валидация цепочки

Ограничения реализации Jsrsasign

При работе с AIA следует учитывать:

  • отсутствие автоматического HTTP fetch
  • необходимость ручной загрузки ресурсов
  • ограниченный high-level API для расширений PKIX

Поэтому AIA обычно используется совместно с внешними HTTP-клиентами (fetch, axios).


Пример полной обработки AIA

async function parseAIA(certPEM) {
  const x = new X509();
  x.readCertPEM(certPEM);

  const exts = x.getExtInfo();
  const result = {
    ocsp: [],
    issuers: []
  };

  exts.forEach(ext => {
    if (ext.extname === "authorityInfoAccess") {
      ext.value.forEach(item => {
        if (item.accessMethod === "1.3.6.1.5.5.7.48.1") {
          result.ocsp.push(item.accessLocation);
        }

        if (item.accessMethod === "1.3.6.1.5.5.7.48.2") {
          result.issuers.push(item.accessLocation);
        }
      });
    }
  });

  return result;
}