Типы ASN.1: UTF8String, PrintableString, IA5String и другие строки

В ASN.1 (Abstract Syntax Notation One) строковые типы используются для строгого представления текстовых данных в сертификатах, ключах и других криптографических структурах. Библиотека jsrsasign реализует поддержку этих типов при формировании и разборе ASN.1-объектов, включая X.509 сертификаты, PKCS#10 запросы и CMS структуры.

Каждый строковый тип ASN.1 отличается набором допустимых символов, правилами кодирования и областью применения. Ошибочный выбор типа может привести к несовместимости с криптографическими библиотеками, отказу валидации сертификата или нарушению стандартов RFC.


UTF8String

UTF8String — один из наиболее универсальных строковых типов ASN.1. Он поддерживает полный набор Unicode-символов, что делает его стандартом де-факто для современных систем.

В jsrsasign UTF8String применяется при кодировании данных, которые могут содержать международные символы, включая кириллицу, иероглифы и специальные знаки.

Основные характеристики:

  • поддержка UTF-8 кодировки
  • возможность использования любых Unicode-символов
  • наиболее предпочтительный тип для современных X.509 сертификатов

Пример использования в структуре ASN.1:

var asn1 = KJUR.asn1;
var utf8 = new asn1.DERUTF8String({
  str: "Пример текста"
});

UTF8String часто используется для полей:

  • subject DN (Distinguished Name)
  • organizationName
  • organizationalUnitName
  • emailAddress (в современных расширениях)

При формировании сертификатов рекомендуется использовать UTF8String по умолчанию, если нет строгих ограничений совместимости.


PrintableString

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

Допустимые символы:

  • A–Z, a–z
  • 0–9
  • пробел
  • символы: ’ ( ) + , - . / : = ?

Особенности:

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

Пример в jsrsasign:

var printable = new KJUR.asn1.DERPrintableString({
  str: "Example Organization"
});

Использование PrintableString характерно для:

  • countryName (C)
  • commonName в старых системах
  • legacy PKI-инфраструктур

При попытке поместить недопустимый символ библиотека может выбросить ошибку или привести к некорректному кодированию.


IA5String

IA5String основан на наборе символов ASCII (IA5 — International Alphabet No. 5). Он поддерживает 7-битную кодировку и используется в специфических полях, где требуется строгая ASCII-совместимость.

Особенности:

  • поддерживает только 128 символов ASCII
  • часто используется в email, URI и DNS-именах
  • не допускает национальных символов

Пример:

var ia5 = new KJUR.asn1.DERIA5String({
  str: "user@example.com"
});

IA5String применяется в:

  • emailAddress (в некоторых профилях сертификатов)
  • uniformResourceIdentifier (URI)
  • domainComponent (в отдельных реализациях X.509)

В отличие от UTF8String, IA5String гарантирует максимальную совместимость с сетевыми протоколами и старыми системами, где Unicode не поддерживается.


BMPString

BMPString (Basic Multilingual Plane String) используется для кодирования символов из базовой многоязычной плоскости Unicode (U+0000 — U+FFFF).

Характеристики:

  • 16-битное кодирование символов
  • поддержка большинства распространённых языков
  • ограничение на символы вне BMP (например, эмодзи)

Пример:

var bmp = new KJUR.asn1.DERBMPString({
  str: "Тестовое значение"
});

BMPString исторически использовался в ранних PKI-реализациях, когда UTF8String ещё не был универсально принят.


T61String (TeletexString)

T61String — устаревший строковый тип, связанный с телетекстовой кодировкой. Используется в старых телекоммуникационных стандартах и ранних версиях X.509.

Особенности:

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

Пример в jsrsasign:

var t61 = new KJUR.asn1.DERT61String({
  str: "Legacy data"
});

В современных системах практически не применяется, но может встречаться в старых сертификатах.


NumericString

NumericString ограничен цифрами и пробелами. Используется в ситуациях, где требуется строго числовое представление данных.

Допустимые символы:

  • 0–9
  • пробел

Пример:

var numeric = new KJUR.asn1.DERNumericString({
  str: "12345 67890"
});

Применение:

  • серийные номера
  • идентификаторы в ограниченных схемах ASN.1
  • legacy телекоммуникационные протоколы

VisibleString (ISO646String)

VisibleString — расширение PrintableString, включающее более широкий набор печатных символов ASCII.

Особенности:

  • включает все печатные ASCII-символы
  • не поддерживает Unicode
  • применяется в старых стандартах X.500

Пример:

var visible = new KJUR.asn1.DERVisibleString({
  str: "Visible text!"
});

UniversalString

UniversalString использует 32-битное кодирование символов Unicode, что обеспечивает максимальную совместимость с расширенными наборами символов.

Особенности:

  • фиксированное 32-битное представление
  • поддержка всех Unicode символов
  • избыточность по сравнению с UTF8String

Пример:

var universal = new KJUR.asn1.DERUniversalString({
  str: "Unicode текст"
});

На практике используется крайне редко из-за большого объёма данных.


UTF8String vs PrintableString в контексте X.509

В структуре X.509 выбор строкового типа влияет на интероперабельность сертификатов между системами.

Типичные правила:

  • UTF8String — основной выбор для современных систем
  • PrintableString — для максимальной обратной совместимости
  • IA5String — для email и URI

Пример конфликтной ситуации:

  • сертификат с кириллицей в PrintableString может быть отклонён
  • тот же сертификат с UTF8String будет корректно принят современными системами

Особенности работы jsrsasign со строками ASN.1

В jsrsasign строковые типы представлены отдельными конструкторами:

  • DERUTF8String
  • DERPrintableString
  • DERIA5String
  • DERBMPString
  • DERNumericString
  • DERVisibleString
  • DERT61String
  • DERUniversalString

Каждый из них наследует общую модель DER-энкодинга и преобразуется в ASN.1 TLV структуру:

  • Tag (идентификатор типа)
  • Length (длина данных)
  • Value (закодированная строка)

Библиотека автоматически выполняет:

  • проверку допустимых символов (в зависимости от типа)
  • кодирование в DER
  • формирование бинарного представления

Ошибки кодирования и ограничения

При работе со строковыми типами часто возникают ошибки:

  • использование кириллицы в PrintableString
  • передача UTF-8 данных в IA5String
  • попытка вставить символы вне ASCII в NumericString

Типичная ошибка в jsrsasign:

  • invalid string for ASN.1 type
  • encoding mismatch
  • illegal character in string

Такие ошибки возникают на этапе построения ASN.1 структуры, до формирования сертификата или запроса.


Практическая совместимость типов

Реальные PKI-системы опираются на строгие профили:

  • RFC 5280 (X.509)
  • CAB Forum Baseline Requirements

В этих документах определено:

  • какие поля должны использовать PrintableString
  • где обязателен UTF8String
  • где допустим IA5String

Нарушение этих правил может привести к:

  • отказу браузеров принимать сертификат
  • ошибкам в цепочке доверия
  • несовместимости между OpenSSL и Java KeyStore

Роль строковых типов в структуре Distinguished Name

Distinguished Name (DN) в X.509 сертификатах представляет собой набор атрибутов, каждый из которых может использовать свой ASN.1 строковый тип:

  • CN (Common Name)
  • O (Organization)
  • OU (Organizational Unit)
  • C (Country)
  • ST (State)
  • L (Locality)

Выбор типа зависит от:

  • требований RFC
  • ограничений системы
  • наличия национальных символов

UTF8String постепенно вытеснил PrintableString в большинстве современных реализаций DN.