TLV (Tag-Length-Value) — базовый способ кодирования структурированных данных, применяемый в ASN.1 и DER-форматах, на которых основаны X.509 сертификаты, ключи, подписи и многие криптографические структуры в JavaScript-библиотеке Jsrsasign.
TLV представляет собой последовательность из трёх компонентов:
Эта модель лежит в основе бинарного представления сложных криптографических объектов, где данные должны быть строго структурированы и однозначно интерпретируемы.
Tag определяет тип закодированного значения. В ASN.1 каждый элемент имеет свой идентификатор, который указывает, как интерпретировать байты Value.
Tag состоит из:
На уровне DER это обычно один или несколько байтов.
Примеры часто встречающихся тегов:
0x02 — INTEGER0x03 — BIT STRING0x04 — OCTET STRING0x05 — NULL0x06 — OBJECT IDENTIFIER0x30 — SEQUENCE (структура, содержащая другие TLV)В Jsrsasign работа с тегами скрыта за высокоуровневыми конструкторами ASN.1, например:
var seq = new KJUR.asn1.DERSequence({
array: [
new KJUR.asn1.DERInteger({int: 3}),
new KJUR.asn1.DERUTF8String({str: "test"})
]
});
Здесь DERSequence автоматически использует тег
0x30, а вложенные элементы получают свои собственные
теги.
Length определяет размер поля Value в байтах. В DER используется два основных варианта кодирования длины:
Если длина меньше 128:
0x00 - 0x7F
Один байт напрямую указывает длину.
Если длина ≥ 128:
Пример:
0x82 0x01 0x2C
Это означает длину 300 (0x012C).
В Jsrsasign разработчик обычно не управляет длиной напрямую. Она вычисляется автоматически при сериализации:
var int = new KJUR.asn1.DERInteger({int: 12345});
console.log(int.getEncodedHex());
Библиотека сама определяет размер Value и формирует корректное поле Length.
Value содержит фактические данные, интерпретируемые согласно Tag.
Это может быть:
Пример структуры SEQUENCE в ASN.1:
SEQUENCE {
INTEGER 10,
OCTET STRING "abc"
}
В Jsrsasign:
var seq = new KJUR.asn1.DERSequence({
array: [
new KJUR.asn1.DERInteger({int: 10}),
new KJUR.asn1.DEROctetString({hex: "616263"})
]
});
Jsrsasign реализует ASN.1 через набор классов
KJUR.asn1.*, где каждый объект соответствует TLV-узлу.
Каждый ASN.1 элемент:
var i = new KJUR.asn1.DERInteger({int: 255});
console.log(i.getEncodedHex());
Результат TLV:
0201FFИтог:
02 01 FF
SEQUENCE позволяет строить иерархические структуры TLV внутри TLV.
Пример:
var seq = new KJUR.asn1.DERSequence({
array: [
new KJUR.asn1.DERInteger({int: 1}),
new KJUR.asn1.DERInteger({int: 2}),
new KJUR.asn1.DERInteger({int: 3})
]
});
Схема:
30 <len>
02 01 01
02 01 02
02 01 03
Здесь:
30 — SEQUENCEJsrsasign позволяет собирать TLV-структуры без использования
высокоуровневых обёрток через ASN1Object:
var asn1 = new KJUR.asn1.ASN1Object();
asn1.hTLV = "020101"; // INTEGER 1
console.log(asn1.getEncodedHex());
Здесь hTLV уже содержит готовую TLV-структуру.
Для декодирования используется ASN1HEX:
var hex = "020101";
var tag = KJUR.asn1.ASN1HEX.getVbyList(hex, 0, ["02"]);
console.log(tag);
Методы:
getTLV() — возвращает TLV блокgetV() — возвращает ValuegetVbyList() — извлекает значение по пути ASN.1
дерева30 06
02 01 01
02 01 02
Разбор:
var hex = "3006020101020102";
var int1 = KJUR.asn1.ASN1HEX.getVbyList(hex, 0, [0,0]);
var int2 = KJUR.asn1.ASN1HEX.getVbyList(hex, 0, [0,1]);
console.log(int1); // 01
console.log(int2); // 02
X.509 полностью построен на TLV-структурах:
Jsrsasign предоставляет:
var x = new X509();
x.readCertHex(certHex);
Внутри происходит разбор TLV дерева.
BIT STRING имеет дополнительный байт в Value:
Пример:
03 03 00 A0 B1
03 — BIT STRING03 — длина00 — padding bitsОбычно используется для хранения:
Jsrsasign:
new KJUR.asn1.DEROctetString({hex: "deadbeef"});
TLV:
04 04 DE AD BE EF
TLV обеспечивает:
Jsrsasign абстрагирует ручную работу с TLV, но вся библиотека фактически является генератором и парсером TLV-последовательностей.
Типичные проблемы:
Jsrsasign обычно предотвращает такие ошибки, но при ручной работе
через ASN1Object они возможны.
Любой ASN.1 объект в библиотеке можно разложить на:
Tag → тип данных
Length → размер Value
Value → данные или вложенные TLV
И вся криптографическая инфраструктура Jsrsasign работает как система генерации и интерпретации таких троек, формируя из них сложные структуры сертификатов, ключей и подписей.