Специфікації ASN.1
Clau компілює специфікації ASN.1 (.asn, .asn1 і списки модулів .set.asn)
у модулі Erlang так само, як asn1ct з OTP: Module.erl з encode/2,
decode/2 і значеннями модуля та Module.hrl з його record і макросами.
Згенерований модуль долучається до пакета компіляції як будь-який інший
вихідний файл; його кодування та декодування виконує рушій BER, DER і PER
мовою C++ у clause_runtime (OpenSSL не потрібна). Специфікації public_key
з OTP компілюватимуться так само.
Вхідні дані
Позиційні вхідні файли із закінченням .asn або .asn1 є специфікаціями:
clau --asn1-option der --asn1-outdir gen Kitchen.asn main.erl -o app
clau --generate-asn1 --asn1-outdir gen Kitchen.asn # only write gen/Kitchen.erl and gen/Kitchen.hrl
| Параметр | Значення |
|---|---|
--asn1-option <option> | Параметр asn1ct для всіх специфікацій виклику; можна повторювати. Типово ber. |
--asn1-outdir <dir> | Куди записуються Module.erl і Module.hrl (outdir в asn1ct); типово поточний каталог. Каталог долучається до шляху включення, тому -include("Module.hrl"). працює. |
--generate-asn1 | Лише записати згенеровані модулі та заголовки; нічого не компілювати. |
-I <dir> | Також використовується для пошуку імпортованих модулів ASN.1 (i в asn1ct), після власного каталогу специфікації. |
Ціль проєкту перелічує специфікації в групах [[targets.asn1]], кожна з яких
компілюється зі своїми параметрами:
[[targets]]
name = "app"
sources = ["src/*.erl"]
[[targets.asn1]]
sources = ["asn1/*.asn"]
options = ["per", "noobj"]
outdir = "build/gen" # default: asn1/ in the target's build directory
sources (обов'язкове) приймає файли та шаблони підстановки так само, як
вихідні файли цілі, зіставляючи .asn і .asn1; відсутність збігів є
помилкою. Імпортовані модулі шукаються в каталогах специфікацій групи.
Згенерований модуль, уже зазначений серед вихідних файлів цілі, не додається
двічі. outdir долучається до шляху включення цілі.
Файл .set.asn перелічує по одному файлу модуля в рядку (об'єднана компіляція
asn1ct); кожна назва перевіряється як записана, потім із доданими .asn1,
.asn та .py. Об'єднаний модуль отримує назву файла набору.
Параметри
| Параметр | Дія |
|---|---|
ber | Базові правила кодування (типово). |
der | Визначені правила кодування: ber із відсортованими SET/SET OF, пропущеними значеннями DEFAULT та перевірками DER. |
maps | Значення SEQUENCE/SET є map; відсутні компоненти пропускаються. |
undec_rest | decode/2 повертає {ok, Value, Rest} із байтами після значення. |
no_ok_wrapper | encode/2 і decode/2 повертають саме значення та породжують винятки в разі помилок. |
legacy_erlang_types | Значення BIT STRING і OCTET STRING як списки, {Unused, Binary} та цілі числа приймаються. |
legacy_bit_string, compact_bit_string | Старі форми BIT STRING (списки 0 і 1, {Unused, Binary}); передбачають legacy_erlang_types. |
noobj, asn1config, verbose, warnings, errors, deterministic | Приймаються, нічого не змінюють. |
per, uper | Упаковані правила кодування, з вирівнюванням і без нього (PER). |
no_final_padding | З uper: encode/2 повертає біти без доповнення до октету (bitstring). |
jer | Відхиляється: jer (JSON encoding rules) is not supported. |
Будь-який інший параметр дає unknown ASN.1 option 'Name' (код виходу 2).
Підтримувані конструкції
Конструкції X.680/X.681/X.682/X.683, які використовують модулі PKIX і PKCS з OTP та специфікації emqx:
- Типи:
BOOLEAN,INTEGERз іменованими числами,ENUMERATEDіз розширеннями,NULL,BIT STRINGз іменованими бітами,OCTET STRING,OBJECT IDENTIFIER,RELATIVE-OID,REAL, обмежені символьні рядки,UTCTime,GeneralizedTime,ObjectDescriptor,SEQUENCE,SET,SEQUENCE OF,SET OF,CHOICE,ANY,ANY DEFINED BY,INSTANCE OF, відкриті типи, типи вибору (name < Type). - Тегування: явні, неявні й автоматичні теги, типові налаштування модуля,
COMPONENTS OF, маркери розширення, групи доповнень розширення та компоненти після розширень. - Обмеження: окремі значення, діапазони,
SIZE,FROM, об'єднання та перетини (обчислюються для меж, які перевіряє BER та кодує PER);WITH COMPONENT(S),CONTAINING,PATTERN,CONSTRAINED BYтаINCLUDESрозбираються, але не перевіряються, як і в asn1ct. - Інформаційні об'єкти: класи з
WITH SYNTAX,TYPE-IDENTIFIER,ABSTRACT-SYNTAX, об'єкти, набори об'єктів (об'єднання, розширювані набори, набори з інших наборів і полів об'єктів), прості табличні обмеження та табличні обмеження зв'язків компонентів ({Set}{@a.b}, декодуються та кодуються через тип об'єкта). - Параметризовані типи, об'єкти й набори об'єктів; імпорти між модулями;
значення
DEFAULTусіх типів.
Не підтримуються; кожна конструкція спричиняє помилку у своїй позиції:
EXTERNAL, EMBEDDED PDV і CHARACTER STRING (unsupported ASN.1 type),
параметризовані значення, об'єкти, видобуті з наборів об'єктів, визначення
MACRO та нотації значень, яких не використовують специфікації OTP
(unsupported value notation).
Згенеровані модулі
Module.erl експортує те саме, що й asn1ct: encoding_rule/0, maps/0,
bit_string_format/0, legacy_erlang_types/0, encode/2, decode/2,
info/0 та по одній функції на кожне присвоєння значення. Record та їхні
назви відповідають asn1ct (внутрішні типи названо за їхнім шляхом,
SEQOF/SETOF для елементів колекцій, параметризовані екземпляри), тому
Module.hrl ідентичний заголовку asn1ct, крім першого рядка коментаря;
значення виводяться так само, як в asn1ct.
encode/2 і decode/2 повертають {ok, Value} або
{error, {asn1, Reason}} із причинами asn1ct ({bad_range, ...},
{unexpected, ...}, {invalid_choice_type, ...},
{'Type not compatible with table constraint', ...}, помилки TLV із
asn1rt_nif); декодування зберігає поблажливість та особливості asn1ct
(невідомі компоненти розширення пропускаються, {asn1_OPENTYPE, Bytes} і
{asn1_ExtAlt, Bytes} для невідомих значень відкритих типів та CHOICE,
{asn1_enum, N}).
Згенеровані функції викликають clause_asn1:encode/3 і
clause_asn1:decode/3 з термом схеми: {asn1_schema, 1, Rule, Flags, #{Type => Node}, Nodes}.
Кожен вузол — це {Kind, Tags, Fields...} (види в порядку NodeKind
компілятора, теги як Number bsl 2 bor Class; межі
{Lower, Upper, Extensible} з кореневими значеннями розширюваного списку
окремих значень як четвертим елементом, обмежені рядки з їхнім алфавітом PER,
компоненти з прапорцем групи доповнення); формат є внутрішнім для Clause та
може змінитися.
PER
per (із вирівнюванням) і uper (без вирівнювання) побайтово відтворюють
код, згенерований asn1ct, та
asn1rtt_per/asn1rtt_uper/asn1rtt_per_common (X.691 у реалізації OTP):
- Видимі для PER обмеження, як їх обчислює
effective_constraint/2в asn1ct: діапазони значень (обмежені, напівобмежені й необмежені цілі числа), межіSIZEнижче 64K (більші кодуються як необмежені довжини), розширювані корені (розширюваний список окремих значень кодує лише ці значення як кореневі) та алфавітиFROMрядків із відомим множником (NumericString,PrintableString,VisibleString,IA5String,BMPString,UniversalString,UTCTime,GeneralizedTime), символи яких є індексами, коли їхні коди не вміщуються в ширину символу. - Кореневі компоненти
SETкодуються в порядку тегів, альтернативиCHOICE— у текстовому порядку (як в asn1ct, а не в канонічному порядку X.691), елементиENUMERATED— за значенням; доповнення розширення є відкритими типами, група доповнення —SEQUENCEзі своїх компонентів; фрагменти понад 16K одиниць (октетів, бітів, символів, елементів). - Особливості asn1ct збережено: у record доповнення розширення після групи
кількох компонентів читаються з неправильних позицій (зсунуті на довжину
групи мінус один); елементи відкритого типу в
SEQUENCE OFігнорують своє табличне обмеження; відкидання кінцевих нульових бітів повністю нульового хвоста іменованогоBIT STRINGзавершується зbadmatch; некоректні вхідні дані спричиняютьbadmatch,case_clauseабоfunction_clauseзгенерованого коду на решті бітів.
Діагностика
Помилки містять шлях, рядок і стовпець специфікації та зупиняють виклик (код виходу 1) до компіляції Erlang:
syntax.asn:4:1: error: expected '::=' near 'END'
undefined.asn:3:22: error: undefined reference Missing
import.asn:4:9: error: cannot find ASN.1 module Absent
empty.asn:1:1: error: no ASN.1 module found
Відмінності від asn1ct перелічено у differences.md.
Clause