FastReport_2022_VCL/LibD28/frxASN1.pas
2024-01-01 16:13:08 +01:00

922 lines
25 KiB
ObjectPascal

unit frxASN1;
{$I frx.inc}
interface
uses
{$IFNDEF Linux}
Windows,
{$ENDIF}
SysUtils, Classes, Math,
frxHelpers;
type
TOIDName = (
OID_undef,
OID_rsaEncryption, // 1.2.840.113549.1.1.1
OID_pkcs7_data, // 1.2.840.113549.1.7.1
OID_pkcs7_signedData, // 1.2.840.113549.1.7.2
OID_pkcs7_envelopedData, // 1.2.840.113549.1.7.3
OID_pkcs7_signedAndEnvelopedData, // 1.2.840.113549.1.7.4
OID_pkcs7_digestedData, // 1.2.840.113549.1.7.5
OID_pkcs7_encryptedData, // 1.2.840.113549.1.7.6
OID_pkcs9_contentType, // 1.2.840.113549.1.9.3
OID_pkcs9_messageDigest, // 1.2.840.113549.1.9.4
OID_friendlyName, // 1.2.840.113549.1.9.20
OID_localKeyID, // 1.2.840.113549.1.9.21
OID_x509Certificate, // 1.2.840.113549.1.9.22.1
OID_pbeWithSHA1And128BitRC4, // 1.2.840.113549.1.12.1.1
OID_pbeWithSHA1And40BitRC4, // 1.2.840.113549.1.12.1.2
OID_pbeWithSHA1And3_KeyTripleDES_CBC, // 1.2.840.113549.1.12.1.3
OID_pbeWithSHA1And2_KeyTripleDES_CBC, // 1.2.840.113549.1.12.1.4
OID_pbeWithSHA1And128BitRC2_CBC, // 1.2.840.113549.1.12.1.5
OID_pbeWithSHA1And40BitRC2_CBC, // 1.2.840.113549.1.12.1.6
OID_keyBag, // 1.2.840.113549.1.12.10.1.1
OID_pkcs_8ShroudedKeyBag, // 1.2.840.113549.1.12.10.1.2
OID_certBag, // 1.2.840.113549.1.12.10.1.3
OID_crlBag, // 1.2.840.113549.1.12.10.1.4
OID_secretBag, // 1.2.840.113549.1.12.10.1.5
OID_safeContentsBag, // 1.2.840.113549.1.12.10.1.6
OID_md5, // 1.2.840.113549.2.5
OID_sha1, // 1.3.14.3.2.26 - US Secure Hash Algorithm 1 (SHA1)
OID_sha256 // 2.16.840.1.101.3.4.2.1
);
TfrxASN1Base = class
private
FTag: Cardinal;
FClass: Byte;
protected
function CalcSize(Value, Threshold, Shift: Cardinal): Cardinal;
function GetTagSize: Cardinal;
function GetLenSize: Cardinal; virtual;
function GetDataSize: Cardinal; virtual;
function GetTotalSize: Cardinal;
function Constructed: Byte; virtual;
function HeaderToAnsi: AnsiString;
function LengthToAnsi: AnsiString; virtual;
function DataToAnsi: AnsiString; virtual;
public
constructor Create(ATag: Cardinal; AClass: Byte);
function ToAnsi: AnsiString;
function CreateCopy: TfrxASN1Base; virtual; abstract;
function IsEqual(ASN1Object: TfrxASN1Base): Boolean; virtual;
function IsTag(ATag: Cardinal): Boolean;
function IsNot(ATag: Cardinal): Boolean;
function IsClass(AClass: Byte): Boolean;
property Tag: Cardinal read FTag;
property ASN1Class: Byte read FClass;
end;
TfrxASN1Null = class(TfrxASN1Base)
protected
public
constructor Create;
function CreateCopy: TfrxASN1Base; override;
end;
TfrxASN1Data = class(TfrxASN1Base)
private
procedure SetData(const Value: AnsiString); virtual;
protected
FData: AnsiString;
function GetDataSize: Cardinal; override;
function DataToAnsi: AnsiString; override;
public
constructor Create(ATag: Cardinal; AClass: Byte; AValue: AnsiString); overload;
constructor Create(AValue: AnsiString); overload;
function CreateCopy: TfrxASN1Base; override;
function IsEqual(ASN1Object: TfrxASN1Base): Boolean; override;
property Data: AnsiString read FData write SetData;
end;
TfrxASN1ImmutableData = class(TfrxASN1Data)
private
procedure SetData(const Value: AnsiString); override;
end;
TfrxASN1Boolean = class(TfrxASN1ImmutableData)
private
FValue: Boolean;
protected
public
constructor Create(AValue: Boolean); overload;
constructor Create(AData: AnsiString); overload;
function CreateCopy: TfrxASN1Base; override;
property Value: Boolean read FValue;
end;
TfrxASN1Integer = class(TfrxASN1ImmutableData)
private
FValue: Int64;
FIsOver64Bit: Boolean;
public
constructor Create(AValue: Int64); overload;
constructor Create(AData: AnsiString); overload;
function CreateCopy: TfrxASN1Base; override;
property Value: Int64 read FValue;
property IsOver64Bit: Boolean read FIsOver64Bit;
end;
TfrxASN1ObjectID = class(TfrxASN1ImmutableData)
private
FOIDName: TOIDName;
public
constructor Create(AData: AnsiString); overload;
constructor Create(AOIDName: TOIDName); overload;
function CreateCopy: TfrxASN1Base; override;
property OIDName: TOIDName read FOIDName;
end;
const
ASN1_TAG_EOC = 0; // End-of-Content
ASN1_TAG_BOOLEAN = 1;
ASN1_TAG_INTEGER = 2;
ASN1_TAG_OCTET_STRING = 4;
ASN1_TAG_NULL = 5;
ASN1_TAG_OBJECT_ID = 6;
ASN1_TAG_SEQUENCE = 16;
ASN1_TAG_SET = 17;
ASN1_CLASS_UNIVERSAL = 0;
ASN1_CLASS_CONTEXT = 2;
type
TfrxASN1Container = class(TfrxASN1Base)
private
FList: TOwnObjList;
FUnknowLength: Boolean;
function GetItems(Index: Integer): TfrxASN1Base;
function GetCount: Integer;
protected
function Constructed: Byte; override;
function GetLenSize: Cardinal; override;
function GetDataSize: Cardinal; override;
function LengthToAnsi: AnsiString; override;
function DataToAnsi: AnsiString; override;
public
constructor Create(ATag: Cardinal; AClass: Byte);
constructor CreateSEQUENCE(AClass: Byte = ASN1_CLASS_UNIVERSAL);
constructor CreateSET;
destructor Destroy; override;
function Add(AObject: TfrxASN1Base): Integer;
function CreateCopy: TfrxASN1Base; override;
function IsEqual(ASN1Object: TfrxASN1Base): Boolean; override;
function IsEmpty: Boolean;
property Items[Index: Integer]: TfrxASN1Base read GetItems; default;
property Count: Integer read GetCount;
end;
TfrxASN1Document = class(TObject)
private
FList: TOwnObjList;
procedure LoadFromBuffer(Buffer: Pointer; Size: Cardinal);
function GetCount: Integer;
function GetItems(Index: Integer): TfrxASN1Base;
public
constructor Create;
destructor Destroy; override;
procedure LoadFromStream(AStream: TStream);
function Add(AObject: TfrxASN1Base): Integer;
procedure Clear;
property Count: Integer read GetCount;
property Items[Index: Integer]: TfrxASN1Base read GetItems; default;
end;
function ReadASN1Object(Data: AnsiString; Offset: Integer = 0): TfrxASN1Base;
procedure RaiseIf(Flag: Boolean; Text: string; DebugLog: TLogList = nil);
implementation
uses
frxNetUtils, frxUtils;
const
OIDData: array[TOIDName, 0..1] of AnsiString = (
(#00, ''), // OID_undef,
(#$2A#$86#$48#$86#$F7#$0D#$01#$01#$01, '1.2.840.113549.1.1.1'), // OID_rsaEncryption,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$01, '1.2.840.113549.1.7.1'), // OID_pkcs7_data,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$02, '1.2.840.113549.1.7.2'), // OID_pkcs7_signedData,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$03, '1.2.840.113549.1.7.3'), // OID_pkcs7_envelopedData,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$04, '1.2.840.113549.1.7.4'), // OID_pkcs7_signedAndEnvelopedData,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$05, '1.2.840.113549.1.7.5'), // OID_pkcs7_digestedData,
(#$2A#$86#$48#$86#$F7#$0D#$01#$07#$06, '1.2.840.113549.1.7.6'), // OID_pkcs7_encryptedData,
(#$2A#$86#$48#$86#$F7#$0D#$01#$09#$03, '1.2.840.113549.1.9.3'), // OID_pkcs9_contentType,
(#$2A#$86#$48#$86#$F7#$0D#$01#$09#$04, '1.2.840.113549.1.9.4'), // OID_pkcs9_messageDigest,
(#$2A#$86#$48#$86#$F7#$0D#$01#$09#$14, '1.2.840.113549.1.9.20'), // OID_friendlyName,
(#$2A#$86#$48#$86#$F7#$0D#$01#$09#$15, '1.2.840.113549.1.9.21'), // OID_localKeyID,
(#$2A#$86#$48#$86#$F7#$0D#$01#$09#$16#$01, '1.2.840.113549.1.9.22.1'), // OID_x509Certificate,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$01, '1.2.840.113549.1.12.1.1'), // OID_pbeWithSHA1And128BitRC4,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$02, '1.2.840.113549.1.12.1.2'), // OID_pbeWithSHA1And40BitRC4,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$03, '1.2.840.113549.1.12.1.3'), // OID_pbeWithSHA1And3_KeyTripleDES_CBC,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$04, '1.2.840.113549.1.12.1.4'), // OID_pbeWithSHA1And2_KeyTripleDES_CBC,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$05, '1.2.840.113549.1.12.1.5'), // OID_pbeWithSHA1And128BitRC2_CBC,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$01#$06, '1.2.840.113549.1.12.1.6'), // OID_pbeWithSHA1And40BitRC2_CBC,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$01, '1.2.840.113549.1.12.10.1.1'), // OID_keyBag,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$02, '1.2.840.113549.1.12.10.1.2'), // OID_pkcs_8ShroudedKeyBag,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$03, '1.2.840.113549.1.12.10.1.3'), // OID_certBag,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$04, '1.2.840.113549.1.12.10.1.4'), // OID_crlBag,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$05, '1.2.840.113549.1.12.10.1.5'), // OID_secretBag,
(#$2A#$86#$48#$86#$F7#$0D#$01#$0C#$0A#$01#$06, '1.2.840.113549.1.12.10.1.6'), // OID_safeContentsBag,
(#$2A#$86#$48#$86#$F7#$0D#$02#$05, '1.2.840.113549.2.5'), // OID_md5,
(#$2B#$0E#$03#$02#$1A, '1.3.14.3.2.26'), // OID_sha1,
(#$60#$86#$48#$01#$65#$03#$04#$02#$01, '2.16.840.1.101.3.4.2.1') // OID_sha256,
);
LEN_LONG = $80; // Indefinite or long length
LEN_MASK = $7F; // 01111111B
TAG_MASK = $1F; // 00011111B
CLASS_MASK = $60; // 01100000B
TAG_MAX = $1E; // 30
LEN_MAX = $7F; // 127
CONSTRUCTED_MASK = $20; // 00100000B
InvalidASN1DocumentCannotCalcula = 'Invalid ASN.1 document. Cannot calculate length or tag.';
{ Utilities }
procedure RaiseIf(Flag: Boolean; Text: string; DebugLog: TLogList = nil);
begin
if Flag then
begin
if Assigned(DebugLog) then
DebugLog.Add(Text);
raise ESignException.Create(Text);
end;
end;
function CreateObject(Tag: Cardinal; AClass: Byte; Data: AnsiString): TfrxASN1Base;
begin
if AClass <> ASN1_CLASS_UNIVERSAL then
Result := TfrxASN1Data.Create(Tag, AClass, Data)
else
case Tag of
ASN1_TAG_BOOLEAN: Result := TfrxASN1Boolean.Create(Data);
ASN1_TAG_NULL: Result := TfrxASN1Null.Create;
ASN1_TAG_INTEGER: Result := TfrxASN1Integer.Create(Data);
ASN1_TAG_OBJECT_ID: Result := TfrxASN1ObjectID.Create(Data);
else
Result := TfrxASN1Data.Create(Tag, AClass, Data);
end;
end;
function DecodeTag(Data: PByteArray; Size: Cardinal; var NextRead: Cardinal): Cardinal;
var
Work: byte;
Res: Int64;
begin
Work := Data[NextRead];
Inc(NextRead);
Work := Work and TAG_MASK;
if Work = TAG_MASK then
begin
Res := 0;
RaiseIf(NextRead >= Size, InvalidASN1DocumentCannotCalcula);
repeat
Work := Data[NextRead];
Inc(NextRead);
Res := (Res shl 7) or (Work and $7F);
RaiseIf(Res > High(Cardinal), 'Invalid ASN.1 document. Very large Tag');
until (NextRead >= Size) or (Work < $80);
Result := Res;
end
else
Result := Work;
end;
function DecodeLen(Data: PByteArray; Size: Cardinal; var NextRead: Cardinal; var UnknowLen: Boolean): Cardinal;
var
LenSize, Work, i: byte;
begin
Result := 0;
Work := Data[NextRead];
Inc(NextRead);
if Work = LEN_LONG then
UnknowLen := True
else if Work and LEN_LONG = 0 then
Result := Work
else
begin
LenSize := Work and LEN_MASK;
RaiseIf(LenSize > 4, 'Invalid ASN.1 document. Very large length.');
for i := 0 to LenSize - 1 do
begin
RaiseIf(NextRead >= Size, InvalidASN1DocumentCannotCalcula);
Work := Data[NextRead];
Inc(NextRead);
Result := (Result shl 8) or Work;
end;
end;
end;
function ASN1ObjName(Tag: Integer): String;
begin
case Tag of
0: Result := '[0]';
ASN1_TAG_BOOLEAN: Result := 'Boolean';
ASN1_TAG_INTEGER: Result := 'Integer';
ASN1_TAG_OCTET_STRING: Result := 'Octet String';
ASN1_TAG_NULL: Result := 'Null';
ASN1_TAG_OBJECT_ID: Result := 'Object ID';
ASN1_TAG_SEQUENCE: Result := 'Sequence';
ASN1_TAG_SET: Result := 'Set';
else
Result := 'Unknown';
end;
end;
//function ASN1ObjValue(Base: TfrxASN1Base): String;
//begin
// if Base is TfrxASN1Boolean then
// Result := IfStr(TfrxASN1Boolean(Base).Value, 'True', 'False')
// else if Base is TfrxASN1Null then
// Result := ''
// else if Base is TfrxASN1Integer then
// Result := IfStr(TfrxASN1Integer(Base).IsOver64Bit, 'Over64Bit', IntToStr(TfrxASN1Integer(Base).Value))
// else if Base is TfrxASN1ObjectID then
// Result := OIDData[TfrxASN1ObjectID(Base).OIDName, 1]
// else if Base is TfrxASN1Container then
// Result := IntToStr(TfrxASN1Container(Base).Count) + ' elem'
// else if Base is TfrxASN1Data then
// Result := AnsiToHex(TfrxASN1Data(Base).Data);
// Result := '(' + Result + ')';
//end;
function ReadItem(List: TOwnObjList; Buffer: Pointer; Offset, Size: Cardinal;
IsUnknowRealSize: Boolean): Cardinal;
const
UnknowRealSize = High(Cardinal);
var
PB: PByteArray;
bClass, Constructed: Byte;
Len, Tag: Cardinal;
IsZeroTagAndLenSource: Boolean;
Container: TfrxASN1Container;
HeaderSize, ItemSize: Cardinal;
NewBuffer: Pointer;
UnknowLen: Boolean;
Data: AnsiString;
begin
Result := 0;
if Offset >= Size then
Exit;
UnknowLen := False;
PB := IncPointer(Buffer, Offset);
bClass := PB[0] shr 6;
Constructed := PB[0] and CONSTRUCTED_MASK;
Tag := DecodeTag(PB, Size - Offset, Result);
RaiseIf(Offset + Result >= Size, InvalidASN1DocumentCannotCalcula);
IsZeroTagAndLenSource := (PB[0] = 0) // Tag Source
and (PB[Result] = 0); // Length Source
if IsZeroTagAndLenSource then
begin
RaiseIf(not IsUnknowRealSize, 'Invalid ASN.1 document. Invalid tag was found');
Result := UnknowRealSize;
Exit;
end;
Len := DecodeLen(PB, Size - Offset, Result, UnknowLen);
HeaderSize := Result;
if not UnknowLen and (Offset + Result + Len > Size) then
Exit;
if Constructed = CONSTRUCTED_MASK then
begin
// OCTET STRING + CONSTRUCTED_MASK => Container ?!
if (bClass <> ASN1_CLASS_UNIVERSAL) or
(Tag in [ASN1_TAG_SEQUENCE, ASN1_TAG_SET, ASN1_TAG_OCTET_STRING]) then
begin
Container := TfrxASN1Container.Create(Tag, bClass);
if UnknowLen then
Len := Size - Offset - HeaderSize;
try
Container.FUnknowLength := UnknowLen;
NewBuffer := IncPointer(Buffer, Offset + HeaderSize);
Offset := 0;
repeat
ItemSize := ReadItem(Container.FList, NewBuffer, Offset, Len, UnknowLen);
if UnknowLen and (ItemSize = UnknowRealSize) then
begin
Inc(Offset, 2);
Break;
end;
Offset := Offset + ItemSize;
until ItemSize = 0;
if UnknowLen then
Len := Offset;
except
Container.Free;
raise;
end;
List.Add(Container);
end
end
else
begin
RaiseIf(UnknowLen, InvalidASN1DocumentCannotCalcula);
SetLength(Data, Len);
Move(PB[Result], Data[1], Len);
List.AddNonZero(CreateObject(Tag, bClass, Data));
end;
Result := Result + Len;
end;
function ReadASN1Object(Data: AnsiString; Offset: Integer = 0): TfrxASN1Base;
var
List: TOwnObjList;
begin
List := TOwnObjList.Create(False);
try
ReadItem(List, @Data[1 + Offset], 0, Length(Data) - Offset, False);
if List.Count = 0 then
Result := nil
else
Result := TfrxASN1Base(List[0]);
finally
List.Free;
end;
end;
function ASN1DecodeDataInteger64(Data: AnsiString): Int64;
var
Len: Cardinal;
B: array[0 .. SizeOf(Int64) - 1] of Byte;
Fill: Byte;
begin
Len := Length(Data);
if Len = 0 then
Result := 0
else
begin
Fill := IfInt(Byte(Data[1]) and $80 <> 0, $FF);
FillChar(B[0], SizeOf(Int64), Fill);
Move(Data[1], B[SizeOf(Int64) - Len], Len);
Result := ByteSwap(PInt64(@B[0])^); // B => Int64
end;
end;
function ASN1EncodeDataInteger64(const Value: Int64): AnsiString;
var
I64: Int64;
Data: AnsiString;
function IsTest(c: AnsiChar; b: Byte): Boolean;
begin
Result := (Data[1] = c) and (Byte(Data[2]) and $80 = b);
end;
begin
I64 := ByteSwap(Value);
SetLength(Data, SizeOf(I64));
Move(I64, Data[1], SizeOf(I64));
while (Length(Data) > 1) and (IsTest(#$00, $00) or IsTest(#$FF, $80)) do
Delete(Data, 1, 1);
Result := Data;
end;
function ASN1EncodeDataBoolean(Value: Boolean): AnsiString;
begin
if Value then Result := #$FF
else Result := #$00;
end;
{ TfrxASN1Base }
function TfrxASN1Base.CalcSize(Value, Threshold, Shift: Cardinal): Cardinal;
begin
Result := 1;
if Value > Threshold then
repeat
Inc(Result);
Value := Value shr Shift;
until Value = 0;
end;
function TfrxASN1Base.Constructed: Byte;
begin
Result := 0;
end;
constructor TfrxASN1Base.Create(ATag: Cardinal; AClass: Byte);
begin
FTag := ATag;
FClass := AClass;
end;
function TfrxASN1Base.DataToAnsi: AnsiString;
begin
Result := '';
end;
function TfrxASN1Base.GetDataSize: Cardinal;
begin
Result := 0;
end;
function TfrxASN1Base.GetLenSize: Cardinal;
begin
Result := CalcSize(GetDataSize, LEN_MAX, 8);
end;
function TfrxASN1Base.GetTagSize: Cardinal;
begin
Result := CalcSize(FTag, TAG_MAX, 7);
end;
function TfrxASN1Base.GetTotalSize: Cardinal;
begin
Result := GetTagSize + GetLenSize + GetDataSize;
end;
function TfrxASN1Base.HeaderToAnsi: AnsiString;
function LongTag(Tag: Cardinal): AnsiString;
var
Bit8: Byte;
begin
Bit8 := 0;
Result := '';
repeat
Result := AnsiChar(Tag and (CLASS_MASK + TAG_MASK) or Bit8) + Result;
Bit8 := $80;
Tag := Tag shr 7;
until Tag = 0;
end;
var
Bits8_6: Byte;
begin
Bits8_6 := (FClass shl 6) or Constructed;
if FTag > TAG_MAX then
Result := AnsiChar(Bits8_6 or TAG_MASK) + LongTag(FTag)
else
Result := AnsiChar(Bits8_6 or FTag);
end;
function TfrxASN1Base.IsClass(AClass: Byte): Boolean;
begin
Result := ASN1Class = AClass;
end;
function TfrxASN1Base.IsEqual(ASN1Object: TfrxASN1Base): Boolean;
begin
Result := (ClassType = ASN1Object.ClassType)
and (FClass = ASN1Object.FClass)
and (FTag = ASN1Object.FTag);
end;
function TfrxASN1Base.IsNot(ATag: Cardinal): Boolean;
begin
Result := Tag <> ATag;
end;
function TfrxASN1Base.IsTag(ATag: Cardinal): Boolean;
begin
Result := Tag = ATag;
end;
function TfrxASN1Base.LengthToAnsi: AnsiString;
var
Len: Cardinal;
Count: Byte;
begin
Len := GetDataSize;
if Len > LEN_MAX then
begin
Result := '';
Count := 0;
while Len > 0 do
begin
Result := AnsiChar(Len and $FF) + Result;
Len := Len shr 8;
Inc(Count);
end;
Result := AnsiChar(Count or $80) + Result;
end
else
Result := AnsiChar(Len);
end;
function TfrxASN1Base.ToAnsi: AnsiString;
begin
Result := HeaderToAnsi + LengthToAnsi + DataToAnsi;
end;
{ TASN1Container }
function TfrxASN1Container.Add(AObject: TfrxASN1Base): Integer;
begin
Result := FList.Add(AObject);
end;
function TfrxASN1Container.Constructed: Byte;
begin
Result := CONSTRUCTED_MASK;
end;
function TfrxASN1Container.CreateCopy: TfrxASN1Base;
var
i: Integer;
R: TfrxASN1Container;
begin
R := TfrxASN1Container.Create(FTag, FClass);
for i := 0 to Count - 1 do
R.Add(Items[i].CreateCopy);
R.FUnknowLength := FUnknowLength;
Result := R;
end;
constructor TfrxASN1Container.CreateSEQUENCE(AClass: Byte = ASN1_CLASS_UNIVERSAL);
begin
Create(ASN1_TAG_SEQUENCE, AClass)
end;
constructor TfrxASN1Container.CreateSET;
begin
Create(ASN1_TAG_SET, ASN1_CLASS_UNIVERSAL);
end;
constructor TfrxASN1Container.Create(ATag: Cardinal; AClass: Byte);
begin
inherited Create(ATag, AClass);
FList := TOwnObjList.Create;
FUnknowLength := False;
end;
destructor TfrxASN1Container.Destroy;
begin
FList.Free;
inherited;
end;
function TfrxASN1Container.GetCount: Integer;
begin
Result := FList.Count;
end;
function TfrxASN1Container.GetDataSize: Cardinal;
var
i: Integer;
begin
Result := 0;
for i := 0 to Count - 1 do
Result := Result + Items[i].GetTotalSize;
if FUnknowLength then
Inc(Result, 2);
end;
function TfrxASN1Container.GetItems(Index: Integer): TfrxASN1Base;
begin
Result := TfrxASN1Base(FList[Index]);
end;
function TfrxASN1Container.GetLenSize: Cardinal;
begin
if FUnknowLength then
Result := 1
else
Result := inherited GetLenSize;
end;
function TfrxASN1Container.IsEmpty: Boolean;
begin
Result := Count < 1;
end;
function TfrxASN1Container.IsEqual(ASN1Object: TfrxASN1Base): Boolean;
var
i: Integer;
begin
Result := inherited IsEqual(ASN1Object)
and (Count = TfrxASN1Container(ASN1Object).Count);
i := 0;
while Result and (i < Count) do
begin
Result := Result and Items[i].IsEqual(TfrxASN1Container(ASN1Object)[i]);
Inc(i);
end;
end;
function TfrxASN1Container.LengthToAnsi: AnsiString;
begin
if FUnknowLength then
Result := #128
else
Result := inherited LengthToAnsi;
end;
function TfrxASN1Container.DataToAnsi: AnsiString;
var
i: Integer;
begin
Result := '';
for i := 0 to Count - 1 do
Result := Result + Items[i].ToAnsi;
if FUnknowLength then
Result := Result + #0#0;
end;
{ TASN1Null }
function TfrxASN1Null.CreateCopy: TfrxASN1Base;
begin
Result := TfrxASN1Null.Create;
end;
constructor TfrxASN1Null.Create;
begin
inherited Create(ASN1_TAG_NULL, ASN1_CLASS_UNIVERSAL);
end;
{ TASN1Boolean }
constructor TfrxASN1Boolean.Create(AData: AnsiString);
begin
RaiseIf(Length(AData) <> 1, 'Invalid ASN.1 document. Tag Boolean length not equal to 1');
Create(AData[1] <> #0);
end;
function TfrxASN1Boolean.CreateCopy: TfrxASN1Base;
begin
Result := TfrxASN1Boolean.Create(FValue);
end;
constructor TfrxASN1Boolean.Create(AValue: Boolean);
begin
inherited Create(ASN1_TAG_BOOLEAN, ASN1_CLASS_UNIVERSAL, ASN1EncodeDataBoolean(AValue));
FValue := AValue;
end;
{ TASN1Integer }
constructor TfrxASN1Integer.Create(AValue: Int64);
begin
inherited Create(ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, ASN1EncodeDataInteger64(AValue));
FValue := AValue;
FIsOver64Bit := False;
end;
function TfrxASN1Integer.CreateCopy: TfrxASN1Base;
begin
Result := TfrxASN1Integer.Create(FData);
end;
constructor TfrxASN1Integer.Create(AData: AnsiString);
begin
inherited Create(ASN1_TAG_INTEGER, ASN1_CLASS_UNIVERSAL, AData);
FIsOver64Bit := Length(AData) > SizeOf(Int64);
if not FIsOver64Bit then
FValue := ASN1DecodeDataInteger64(AData);
end;
{ TASN1Document }
function TfrxASN1Document.Add(AObject: TfrxASN1Base): Integer;
begin
Result := FList.Add(AObject);
end;
procedure TfrxASN1Document.Clear;
begin
FList.Clear;
end;
constructor TfrxASN1Document.Create;
begin
FList := TOwnObjList.Create;
end;
destructor TfrxASN1Document.Destroy;
begin
FList.Free;
inherited;
end;
function TfrxASN1Document.GetCount: Integer;
begin
Result := FList.Count;
end;
function TfrxASN1Document.GetItems(Index: Integer): TfrxASN1Base;
begin
Result := TfrxASN1Base(FList[Index]);
end;
procedure TfrxASN1Document.LoadFromBuffer(Buffer: Pointer; Size: Cardinal);
var
Offset: Cardinal;
ItemSize: Cardinal;
begin
FList.Clear;
Offset := 0;
repeat
ItemSize := ReadItem(FList, Buffer, Offset, Size, False);
Offset := Offset + ItemSize;
until ItemSize = 0;
end;
procedure TfrxASN1Document.LoadFromStream(AStream: TStream);
var
Buffer: Pointer;
Size, OldPosition: Cardinal;
begin
Size := AStream.Size - AStream.Position;
Buffer := GetMemory(Size);
try
OldPosition := AStream.Position;
AStream.Read(Buffer^, Size);
AStream.Position := OldPosition;
LoadFromBuffer(Buffer, Size);
finally
FreeMemory(Buffer);
end;
end;
{ TASN1Data }
function TfrxASN1Data.CreateCopy: TfrxASN1Base;
begin
Result := TfrxASN1Data.Create(FTag, FClass, FData);
end;
constructor TfrxASN1Data.Create(AValue: AnsiString);
begin
Create(ASN1_TAG_OCTET_STRING, ASN1_CLASS_UNIVERSAL, AValue);
end;
constructor TfrxASN1Data.Create(ATag: Cardinal; AClass: Byte; AValue: AnsiString);
begin
inherited Create(ATag, AClass);
FData := AValue;
end;
function TfrxASN1Data.GetDataSize: Cardinal;
begin
Result := Length(FData);
end;
function TfrxASN1Data.IsEqual(ASN1Object: TfrxASN1Base): Boolean;
begin
Result := inherited IsEqual(ASN1Object)
and (FData = TfrxASN1Data(ASN1Object).FData);
end;
procedure TfrxASN1Data.SetData(const Value: AnsiString);
begin
FData := Value;
end;
function TfrxASN1Data.DataToAnsi: AnsiString;
begin
Result := FData;
end;
{ TASN1ObjectID }
function TfrxASN1ObjectID.CreateCopy: TfrxASN1Base;
begin
Result := TfrxASN1ObjectID.Create(FData);
end;
constructor TfrxASN1ObjectID.Create(AData: AnsiString);
var
OIDName: TOIDName;
begin
inherited Create(ASN1_TAG_OBJECT_ID, ASN1_CLASS_UNIVERSAL, AData);
FOIDName := OID_undef;
for OIDName := Low(TOIDName) to High(TOIDName) do
if FData = OIDData[OIDName, 0] then
begin
FOIDName := OIDName;
Break;
end;
end;
constructor TfrxASN1ObjectID.Create(AOIDName: TOIDName);
begin
Create(OIDData[AOIDName, 0]);
end;
{ TASN1ImmutableData }
procedure TfrxASN1ImmutableData.SetData(const Value: AnsiString);
begin
raise ESignException.Create('Cannot change ASN.1 value for this class');
end;
end.