PDFiumPas 文件

FPdfAsn1 單元

單元: FPdfAsn1
以有界的資源使用量,編碼、導覽、解碼並驗證 ASN.1 Distinguished Encoding Rules 資料

Public Types

TypeDescription
TAsnTag通用標籤常數(BOOLEAN、INTEGER、OCTET STRING、OID、SEQUENCE、SET、時間與字串形式),用於識別碼建構與驗證
TAsnClass識別碼類別:asnClassUniversal、asnClassApplication、asnClassContextSpecific 或 asnClassPrivate
TAsnIdentifier識別碼類別、建構旗標與 64 位元標籤編號,包含高標籤編號形式
TDerTlv已剖析的 TLV,含 Offset、HeaderLength、ContentOffset、ContentLength、NextOffset 與 Identifier,不複製來源緩衝區
TDerWriter可重複使用的 DER 輸出緩衝區與型別化編碼器
TDerReader有界的讀取器,具備窺視、前進、略過、預期標籤、子視窗、切片與型別化解碼作業
TDerByteArraysTBytes 的動態陣列,供 ConcatMany 與其他多緩衝區輔助函式使用
TDerValidationErrorKind驗證錯誤類別:dvekMalformedTlv、dvekTrailingData、深度、節點與內容限制(dvekDepthLimit、dvekNodeLimit、dvekContentLimit)、dvekUniversalForm、逐型別的正規形式失敗(dvekBoolean、dvekInteger、dvekBitString、dvekNull、dvekOid、dvekString、dvekTime),以及 dvekSetOrder
TDerValidationError具位移與 Depth 資訊的錯誤記錄,含 Kind 與人類可讀的訊息文字
TDerValidationErrorsTDerValidationError 的動態陣列,於 TDerValidationResult 內傳回
TDerValidationOptionsMaxDepth、MaxNodes、MaxContentLength、MaxErrors 限制、RequireSingleRoot 旗標、選用的 ValidateSetOrder,以及 Default 類別函式
TDerValidationResult驗證狀態,含 IsValid、NodeCount、MaximumDepth、具位移資訊的 Errors,以及 ErrorCount 與 FirstError 輔助

寫入 API

APIDescription
Clear、IsEmpty、Count、Capacity、Bytes、Finish重設或檢查緩衝資料、複製快照,或移交完成的陣列並重設寫入器
Reserve、Append、AppendMany、AppendByte成長一次並附加陣列、呼叫端擁有的緩衝區、多個陣列或單一位元組,附溢位檢查
Wrap、WrapIdentifier、WrapConstructed以原始識別碼位元組、任意識別碼類別與 64 位元標籤編號,或建構式識別碼包裝內容
ContextSpecific、ApplicationSpecific、PrivateSpecific編碼低或高標籤編號,不截斷識別碼
Sequence、SequenceOf、SetOf、SetOfSorted將已編碼值組成 SEQUENCE 或 SET 容器;SetOfSorted 依編碼位元組排序值
BooleanOf、IntegerOf、UnsignedIntegerOf、IntegerBytes、EnumeratedOf編碼 BOOLEAN、帶號或無號 INTEGER、已驗證的任意 INTEGER 內容,以及 ENUMERATED 值
OctetString、OctetStringOf、BitString、Null、OID將二進位、位元字串、NULL 與物件識別碼值編碼為獨立 TLV
PrintableString、Ia5String、Utf8String編碼受支援的 ASN.1 字元字串形式
UTCTime、GeneralizedTime、UTCTimeOf、GeneralizedTimeOf、TimeOf編碼正規時間文字或 UTC TDateTime 值,TimeOf 會選擇正確的 DER 時間型別
AlgId、AlgIdWithParams以 NULL 或明確參數建構 AlgorithmIdentifier SEQUENCE

讀取 API

APIDescription
Initialize、AtEnd、EffectiveLimit、Remaining初始化讀取器並檢查其有界視窗與剩餘位元組數
TryReadTlvAt、PeekTlv剖析低或高標籤編號與最短定長,而不改變 Position
ReadNextTlv、SkipTlv只有在完整有效的 TLV 可用時才前進
TryReadExpected只有在類別、建構形式與標籤編號全部相符時才前進
EnterConstructed在相同來源陣列上建立子讀取器視窗,不複製內容
ContentBytes、EncodedBytes需要取得所有權時,複製已驗證的內容或完整 TLV 切片
TryReadBoolean、TryReadUnsignedInteger、TryReadBitString以範圍與未用位元檢查解碼正規的基本值
TryReadString、TryReadTime、TryReadNull解碼已驗證的 UTF8String、PrintableString、IA5String、DER 時間或 NULL 內容
ReadTlv、TryReadOID、ReadOID、TryReadInteger、ReadInteger提供對原始 TLV 位移的相容存取,外加物件識別碼與帶號整數解碼

驗證

function ValidateDer(const Data: TBytes): TDerValidationResult; overload;
function ValidateDer(const Data: TBytes; const Options: TDerValidationOptions): TDerValidationResult; overload;

ValidateDer 檢查識別碼與長度最簡性、緩衝區邊界、通用基本形式、BOOLEAN、INTEGER、ENUMERATED、BIT STRING、NULL、OBJECT IDENTIFIER、受支援的字串與正規時間值

預設限制允許最大深度 64、100000 個節點、每個內容值 64 MiB 與 32 筆錯誤回報,並要求單一根 TLV

ValidateSetOrder 預設停用,因為無綱要的 DER 無法區分每個 SET 與 SET OF;針對已知的 SET OF 容器(例如 CMS 屬性集合)請啟用它

TDerValidationOptions.Default 提供有界的預設值,而 TDerValidationResult.ErrorCount 與 FirstError 簡化診斷處理

公用輔助函式

function AsnIdentifier(TagClass: TAsnClass; TagNumber: UInt64; Constructed: Boolean = False): TAsnIdentifier;
function EncodeIdentifier(const Identifier: TAsnIdentifier): TBytes;
function ConcatBytes(const A, B: TBytes): TBytes;
function Concat3(const A, B, C: TBytes): TBytes;
function Concat4(const A, B, C, D: TBytes): TBytes;
function ConcatMany(const Values: TDerByteArrays): TBytes;
function EncodeOIDContent(const Dotted: AnsiString): TBytes;
function DerValidationErrorKindName(Kind: TDerValidationErrorKind): string;

FunctionDescription
AsnIdentifier從類別、標籤編號與建構旗標建構 TAsnIdentifier,用於驅動 TDerReader.TryReadExpected
EncodeIdentifier將 TAsnIdentifier 編碼為其 DER 識別碼位元組,包含高標籤編號形式
ConcatBytes、Concat3、Concat4、ConcatMany將兩、三、四個或動態陣列的 TBytes 串接為單一配置;CMS 建構器廣泛使用
EncodeOIDContent將點分隔十進位 OID 字串編碼為其內容位元組(不含標籤與長度),讓呼叫端可檢查或重新包裝 OID
DerValidationErrorKindName傳回 TDerValidationErrorKind 的顯示名稱,供診斷使用

Example

uses FPdfAsn1;

var
  Child: TDerReader;
  Data: TBytes;
  Reader: TDerReader;
  Tlv: TDerTlv;
  Validation: TDerValidationResult;
  Writer: TDerWriter;
begin
  Writer := TDerWriter.Create;
  try
    Data := Writer.Sequence(Writer.UnsignedIntegerOf(42));
  finally
    Writer.Free;
  end;

  Validation := ValidateDer(Data);
  if not Validation.IsValid then
    raise EConvertError.Create(Validation.Errors[0].MessageText);

  Reader.Initialize(Data);
  if Reader.TryReadExpected(AsnIdentifier(asnClassUniversal, 16, True), Tlv) then
    Reader.EnterConstructed(Tlv, Child);
end;

Remarks