|
@@ -5,7 +5,7 @@ unit fpasn;
|
|
|
interface
|
|
|
|
|
|
uses
|
|
|
- Basenenc, Classes, SysUtils, fphashutils;
|
|
|
+ Basenenc, Classes, SysUtils, fphashutils;
|
|
|
|
|
|
const
|
|
|
ASN1_BOOL = $01;
|
|
@@ -49,29 +49,26 @@ const
|
|
|
//------------------------------------------------------------------------------
|
|
|
// ASN
|
|
|
//------------------------------------------------------------------------------
|
|
|
-procedure ASNEncodeOID(const Value: Int64; var Result: AnsiString);
|
|
|
-function ASNDecodeOID(var Start: Integer; const S: AnsiString): Int64; overload;
|
|
|
+procedure ASNEncodeOID(const Value: Int64; var Result: String);
|
|
|
+function ASNDecodeOID(var Start: Integer; const S: String): Int64; overload;
|
|
|
function ASNDecodeOID(var Buffer: PByte; BufferEnd: PByte): Int64; overload;
|
|
|
function ASNGetEncodedLen(const Len: Integer): Integer;
|
|
|
procedure ASNEncodeLen(const Len: Integer; var Buffer: TBytes);
|
|
|
-function ASNReadLen(const Buffer: TBytes; var Offset: Int32): Int32;
|
|
|
+function ASNReadLen(var Buffer: PByte; BufferEnd: PByte): Int32;
|
|
|
procedure ASNEncodeInt(Value: Int64; var Result: TBytes);
|
|
|
procedure ASNEncodeUInt(Value: Integer; var Result: TBytes);
|
|
|
// Encodes ASN.1 object to binary form
|
|
|
-procedure ASNObject(const Data: Ansistring; const ASNType: Integer; var Buffer: TBytes);
|
|
|
-// Encodes an MIB OID Ansistring to binary form
|
|
|
-procedure MibToId(Mib: Ansistring; var Result: AnsiString);
|
|
|
-// Decodes MIB OID from binary form to Ansistring form.
|
|
|
-procedure IdToMib(const Id: Ansistring; var Result: Ansistring); overload;
|
|
|
+procedure ASNObject(const Data: String; const ASNType: Integer; var Buffer: TBytes);
|
|
|
+// Encodes an MIB OID String to binary form
|
|
|
+procedure MibToId(Mib: String; var Result: String);
|
|
|
+// Decodes MIB OID from binary form to String form.
|
|
|
+procedure IdToMib(const Id: String; var Result: String); overload;
|
|
|
function IdToMib(Buffer, BufferEnd: PByte): string; overload;
|
|
|
procedure ASNDebug(const Buffer: TBytes; var Output: TBytes);
|
|
|
procedure ASNParse(const Buffer: TBytes; List: TStrings);
|
|
|
-procedure PemToDER(const PEM: AnsiString; const BeginTag, EndTag: Ansistring; Out DER: TBytes); overload;
|
|
|
-procedure PemToDER(PEM: TBytes; const BeginTag, EndTag: Ansistring; Out DER: TBytes); overload;
|
|
|
-procedure ASNParsePemSection(const PEM: TBytes; List: TStrings; const BeginTag, EndTag: Ansistring);
|
|
|
-procedure ASNParsePemSection(const PEM: AnsiString; List: TStrings; const BeginTag, EndTag: Ansistring);
|
|
|
+procedure ASNParse_GetItem(List: TStrings; Index: integer; out ASNType, ASNSize: integer);
|
|
|
+function ASNParse_GetIntBytes(List: TStrings; ListIndex: integer; ID: int64): TBytes;
|
|
|
|
|
|
-function ASNFetch(const Buffer: TBytes; var Offset: Int32; Out ASNType, ASNSize: Int32): Boolean; overload;
|
|
|
function ASNFetch(var Buffer: PByte; BufferEnd: PByte; Out ASNType, ASNSize: Int32): Boolean; overload;
|
|
|
function ASNFetchOID(var Buffer: PByte; BufferEnd: PByte; out OID: String): Boolean; overload;
|
|
|
|
|
@@ -81,13 +78,13 @@ implementation
|
|
|
// ASN
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
-procedure ASNEncodeOID(const Value: Int64; var Result: Ansistring);
|
|
|
+procedure ASNEncodeOID(const Value: Int64; var Result: String);
|
|
|
var
|
|
|
B: Boolean;
|
|
|
I: Integer;
|
|
|
x: Int64;
|
|
|
Modulo: Byte;
|
|
|
- S: Ansistring;
|
|
|
+ S: String;
|
|
|
|
|
|
begin
|
|
|
S:='';
|
|
@@ -107,7 +104,7 @@ begin
|
|
|
end;
|
|
|
|
|
|
// @Start=0
|
|
|
-function ASNDecodeOID(var Start: Integer; const S: AnsiString): Int64;
|
|
|
+function ASNDecodeOID(var Start: Integer; const S: String): Int64;
|
|
|
var
|
|
|
x: Integer;
|
|
|
begin
|
|
@@ -138,7 +135,7 @@ end;
|
|
|
procedure ASNEncodeLen(const Len: Integer; var Buffer: TBytes);
|
|
|
var
|
|
|
x, y: Integer;
|
|
|
- S: AnsiString;
|
|
|
+ S: String;
|
|
|
|
|
|
begin
|
|
|
if Len < $80 then
|
|
@@ -175,25 +172,24 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-function ASNReadLen(const Buffer: TBytes; var Offset: Int32): Int32;
|
|
|
+function ASNReadLen(var Buffer: PByte; BufferEnd: PByte): Int32;
|
|
|
var
|
|
|
Len: Integer;
|
|
|
begin
|
|
|
- Result := Buffer[Offset];
|
|
|
- Inc(Offset);
|
|
|
+ if Buffer>BufferEnd then
|
|
|
+ raise Exception.Create('20220428135218');
|
|
|
+ Result := Buffer^;
|
|
|
+ Inc(Buffer);
|
|
|
if Result < $80 then
|
|
|
Exit;
|
|
|
Len := Result and $7F;
|
|
|
- if (Len>4) or (Offset+Len >= length(Buffer)) then
|
|
|
- begin
|
|
|
- Offset:=length(Buffer)+1;
|
|
|
- exit;
|
|
|
- end;
|
|
|
+ if (Len>4) or (BufferEnd-Buffer < Len) then
|
|
|
+ raise Exception.Create('20220428135333');
|
|
|
Result := 0;
|
|
|
while Len > 0 do
|
|
|
begin
|
|
|
- Result := Result*256 + Buffer[Offset];
|
|
|
- Inc(Offset);
|
|
|
+ Result := Result*256 + Buffer^;
|
|
|
+ Inc(Buffer);
|
|
|
Dec(Len);
|
|
|
end;
|
|
|
end;
|
|
@@ -204,7 +200,7 @@ var
|
|
|
x: Int64;
|
|
|
y: byte;
|
|
|
neg: Boolean;
|
|
|
- S : AnsiString;
|
|
|
+ S : String;
|
|
|
begin
|
|
|
S:='';
|
|
|
neg := Value < 0;
|
|
@@ -230,7 +226,7 @@ procedure ASNEncodeUInt(Value: Integer; var Result: TBytes);
|
|
|
var
|
|
|
x, y: Integer;
|
|
|
neg: Boolean;
|
|
|
- S : AnsiString;
|
|
|
+ S : String;
|
|
|
|
|
|
begin
|
|
|
neg := Value < 0;
|
|
@@ -249,7 +245,7 @@ begin
|
|
|
Result:=Concat(Result,[Ord(S[y])]);
|
|
|
end;
|
|
|
|
|
|
-Procedure AppendStringToBuffer(var Buffer: TBytes; const aString : AnsiString);
|
|
|
+Procedure AppendStringToBuffer(var Buffer: TBytes; const aString : String);
|
|
|
|
|
|
Var
|
|
|
Buflen,sLen : integer;
|
|
@@ -262,7 +258,7 @@ begin
|
|
|
Move(aString[1],Buffer[Buflen],sLen);
|
|
|
end;
|
|
|
|
|
|
-procedure ASNObject(const Data: AnsiString; const ASNType: Integer; var Buffer: TBytes);
|
|
|
+procedure ASNObject(const Data: String; const ASNType: Integer; var Buffer: TBytes);
|
|
|
|
|
|
|
|
|
begin
|
|
@@ -271,7 +267,7 @@ begin
|
|
|
AppendStringToBuffer(Buffer,Data);
|
|
|
end;
|
|
|
|
|
|
-procedure DumpExStr(const S: AnsiString; var Output: TBytes);
|
|
|
+procedure DumpExStr(const S: String; var Output: TBytes);
|
|
|
var
|
|
|
I: Integer;
|
|
|
x: Byte;
|
|
@@ -291,7 +287,7 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-procedure OutputHexa(var Output: TBytes; const S: AnsiString);
|
|
|
+procedure OutputHexa(var Output: TBytes; const S: String);
|
|
|
|
|
|
var
|
|
|
I: Integer;
|
|
@@ -307,9 +303,9 @@ begin
|
|
|
end;
|
|
|
|
|
|
// @Result[256]
|
|
|
-procedure MibToId(Mib: AnsiString; var Result: AnsiString);
|
|
|
+procedure MibToId(Mib: String; var Result: String);
|
|
|
|
|
|
- function WalkInt(var S: AnsiString): Integer;
|
|
|
+ function WalkInt(var S: String): Integer;
|
|
|
var
|
|
|
P : Integer;
|
|
|
|
|
@@ -335,7 +331,7 @@ begin
|
|
|
end;
|
|
|
|
|
|
// @Result[256]
|
|
|
-procedure IdToMib(const ID: AnsiString; var Result: AnsiString);
|
|
|
+procedure IdToMib(const Id: String; var Result: String);
|
|
|
var
|
|
|
x, y, Index: Integer;
|
|
|
begin
|
|
@@ -354,7 +350,7 @@ begin
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-function ASNParseInt(const Buffer: TBytes; var Start: Integer; const ASNSize: Integer): Int64;
|
|
|
+function ASNParseInt(var Buffer: PByte; BufferEnd: PByte; const ASNSize: Integer): Int64;
|
|
|
var
|
|
|
I: Integer;
|
|
|
Negative: Boolean;
|
|
@@ -364,64 +360,73 @@ begin
|
|
|
Negative := False;
|
|
|
for I := 1 to ASNSize do
|
|
|
begin
|
|
|
- X := Buffer[Start];
|
|
|
+ if Buffer>=BufferEnd then
|
|
|
+ raise Exception.Create('20220428134948');
|
|
|
+ X := Buffer^;
|
|
|
if (I = 1) and (X > $7F) then
|
|
|
Negative := True;
|
|
|
if Negative then
|
|
|
X := not X;
|
|
|
Result := Result*256 + X;
|
|
|
- Inc(Start);
|
|
|
+ if Result>high(longint) then
|
|
|
+ raise Exception.Create('20220428135614');
|
|
|
+ Inc(Buffer);
|
|
|
end;
|
|
|
if Negative then
|
|
|
Result := -(Result + 1);
|
|
|
end;
|
|
|
|
|
|
-function ASNParseUInt(const Buffer: TBytes; var Start: Integer; const ASNSize: Integer): Int64;
|
|
|
+function ASNParseUInt(var Buffer: PByte; BufferEnd: PByte; const ASNSize: Integer): Int64;
|
|
|
var
|
|
|
I: Integer;
|
|
|
begin
|
|
|
Result := 0;
|
|
|
for I := 1 to ASNSize do
|
|
|
begin
|
|
|
- Result := Result*256 + Buffer[Start];
|
|
|
- Inc(Start);
|
|
|
+ if Buffer>=BufferEnd then
|
|
|
+ raise Exception.Create('20220428135002');
|
|
|
+ Result := Result*256 + Buffer^;
|
|
|
+ if Result>high(dword) then
|
|
|
+ raise Exception.Create('20220428135614');
|
|
|
+ Inc(Buffer);
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-// Beginning with the @Start position, decode the ASN.1 item of the next element in @Buffer. Type of item is stored in @ASNType
|
|
|
-procedure ASNDebugItem(const Buffer: TBytes; var Start: Integer; Out ASNType, ASNSize: Integer; var Output: TBytes);
|
|
|
+// Decode the ASN.1 item of the next element in @Buffer. Type of item is stored in @ASNType
|
|
|
+procedure ASNDebugItem(var Buffer: PByte; BufferEnd: PByte; Out ASNType, ASNSize: Integer; var Output: TBytes);
|
|
|
|
|
|
- procedure BufToString(out S : AnsiString);
|
|
|
+ procedure BufToString(out S : String);
|
|
|
|
|
|
begin
|
|
|
S:='';
|
|
|
SetLength(S,ASNSize);
|
|
|
if ASNSize>0 then
|
|
|
- Move(Buffer[Start],S[1],ASNSize);
|
|
|
+ begin
|
|
|
+ Move(Buffer^,S[1],ASNSize);
|
|
|
+ inc(Buffer,ASNSize);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
-
|
|
|
var
|
|
|
- l, n: Integer;
|
|
|
- S, S2: AnsiString;
|
|
|
+ n: Integer;
|
|
|
+ S, S2: String;
|
|
|
y: Int64;
|
|
|
+ OldBuffer: PByte;
|
|
|
begin
|
|
|
S:='';
|
|
|
S2:='';
|
|
|
ASNType := ASN1_NULL;
|
|
|
- l := Length(Buffer);
|
|
|
- if Start > l then
|
|
|
+ if Buffer>=BufferEnd then
|
|
|
Exit;
|
|
|
- ASNType := Buffer[Start];
|
|
|
- Inc(Start);
|
|
|
- ASNSize := ASNReadLen(Buffer, Start);
|
|
|
- if (Start + ASNSize) > l then
|
|
|
+ ASNType := Buffer^;
|
|
|
+ Inc(Buffer);
|
|
|
+ ASNSize := ASNReadLen(Buffer, BufferEnd);
|
|
|
+ if BufferEnd-Buffer < ASNSize then
|
|
|
Exit;
|
|
|
AppendStringToBuffer(Output,'$');
|
|
|
AppendStringToBuffer(Output, HexStr(ASNType,2));
|
|
|
if (ASNType and $20) > 0 then
|
|
|
begin
|
|
|
-// XBufferAppend(Output, Buffer, Start, ASNSize)
|
|
|
if ASNType = ASN1_SEQ then
|
|
|
AppendStringToBuffer(Output, ' SEQUENCE: length ')
|
|
|
else if ASNType = ASN1_SETOF then
|
|
@@ -442,7 +447,7 @@ begin
|
|
|
AppendStringToBuffer(Output, ' ENUM: ');
|
|
|
if ASNSize < 8 then
|
|
|
begin
|
|
|
- y := ASNParseInt(Buffer, Start, ASNSize);
|
|
|
+ y := ASNParseInt(Buffer, BufferEnd, ASNSize);
|
|
|
AppendStringToBuffer(Output, IntToStr(y));
|
|
|
end else
|
|
|
begin
|
|
@@ -451,7 +456,6 @@ begin
|
|
|
Delete(S,1,1);
|
|
|
AppendStringToBuffer(Output, '$');
|
|
|
OutputHexa(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
end;
|
|
|
ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS, ASN1_COUNTER64:
|
|
@@ -466,14 +470,13 @@ begin
|
|
|
AppendStringToBuffer(Output, ' COUNTER64: ');
|
|
|
if ASNSize < 8 then
|
|
|
begin
|
|
|
- y := ASNParseUInt(Buffer, Start, ASNSize);
|
|
|
+ y := ASNParseUInt(Buffer, BufferEnd, ASNSize);
|
|
|
AppendStringToBuffer(Output, IntToStr(y));
|
|
|
end else
|
|
|
begin
|
|
|
BufToString(S);
|
|
|
AppendStringToBuffer(Output, '$');
|
|
|
OutputHexa(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
end;
|
|
|
ASN1_OCTSTR, ASN1_OPAQUE:
|
|
@@ -484,27 +487,26 @@ begin
|
|
|
AppendStringToBuffer(Output, ' OPAQUE: ');
|
|
|
BufToString(S);
|
|
|
OutputHexa(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
ASN1_UTCTIME:
|
|
|
begin // 180131123456Z -> 2018-01-31 12:34:56
|
|
|
AppendStringToBuffer(Output, ' UTCTIME: ');
|
|
|
BufToString(S);
|
|
|
AppendStringToBuffer(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
ASN1_BITSTR:
|
|
|
begin
|
|
|
AppendStringToBuffer(Output, ' BITSTR: ');
|
|
|
- Inc(Start); // this is the Trailing Length in bits
|
|
|
+ Inc(Buffer); // this is the Trailing Length in bits
|
|
|
Dec(ASNSize);
|
|
|
+ OldBuffer:=Buffer;
|
|
|
BufToString(S);
|
|
|
OutputHexa(Output, S);
|
|
|
- if (ASNType = ASN1_BITSTR) and (Buffer[Start] = ASN1_SEQ) then
|
|
|
+ if (ASNType = ASN1_BITSTR) and (OldBuffer^ = ASN1_SEQ) then
|
|
|
begin
|
|
|
// continue to decode the bitstring as ASN.1 formatted content
|
|
|
- end else
|
|
|
- Inc(Start, ASNSize);
|
|
|
+ Buffer:=OldBuffer;
|
|
|
+ end;
|
|
|
end;
|
|
|
ASN1_UTF8STRING, ASN1_PRINTABLESTRING, ASN1_IA5STRING:
|
|
|
begin
|
|
@@ -516,7 +518,6 @@ begin
|
|
|
AppendStringToBuffer(Output, ' IA5STRING: ');
|
|
|
BufToString(S);
|
|
|
AppendStringToBuffer(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
ASN1_OBJID:
|
|
|
begin
|
|
@@ -525,31 +526,29 @@ begin
|
|
|
S:='';
|
|
|
IdToMib(S2, S);
|
|
|
AppendStringToBuffer(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
ASN1_IPADDR:
|
|
|
begin
|
|
|
AppendStringToBuffer(Output, ' IPADDR: ');
|
|
|
for n := 1 to ASNSize do
|
|
|
begin
|
|
|
- if n <> 1 then
|
|
|
+ if n > 1 then
|
|
|
AppendStringToBuffer(Output, '.');
|
|
|
- y := Buffer[Start];
|
|
|
- Inc(Start);
|
|
|
+ y := Buffer^;
|
|
|
+ Inc(Buffer);
|
|
|
AppendStringToBuffer(Output, IntToStr(y));
|
|
|
end;
|
|
|
end;
|
|
|
ASN1_NULL:
|
|
|
begin
|
|
|
AppendStringToBuffer(Output, ' NULL: ');
|
|
|
- Inc(Start, ASNSize);
|
|
|
+ Inc(Buffer, ASNSize);
|
|
|
end;
|
|
|
else // unknown
|
|
|
begin
|
|
|
AppendStringToBuffer(Output, ' unknown: ');
|
|
|
BufToString(S);
|
|
|
OutputHexa(Output, S);
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
@@ -577,94 +576,76 @@ end;
|
|
|
procedure ASNDebug(const Buffer: TBytes; var Output: TBytes);
|
|
|
|
|
|
const
|
|
|
- SSpaces: AnsiString = ' ';
|
|
|
+ SSpaces: String = ' ';
|
|
|
|
|
|
var
|
|
|
- ASNSize, ASNType, Index, n: Integer;
|
|
|
+ ASNSize, ASNType, n: Integer;
|
|
|
Indent: Integer;
|
|
|
IndentList: Array of Integer;
|
|
|
+ p, EndP: PByte;
|
|
|
|
|
|
begin
|
|
|
+ if length(Buffer)=0 then exit;
|
|
|
IndentList:=[];
|
|
|
Indent:=0;
|
|
|
- Index := 0;
|
|
|
- while Index < Length(Buffer) do
|
|
|
+ p:=@Buffer[0];
|
|
|
+ EndP:=p+length(Buffer);
|
|
|
+ while p<EndP do
|
|
|
begin
|
|
|
+ // check if any sequence/set has ended and unindent
|
|
|
for n := Length(IndentList)-1 downto 0 do
|
|
|
begin
|
|
|
ASNSize := IndentList[n];
|
|
|
- if ASNSize <= Index then
|
|
|
+ if EndP-p >= ASNSize then
|
|
|
begin
|
|
|
Delete(IndentList,n,1);
|
|
|
Dec(Indent, 2);
|
|
|
end;
|
|
|
end;
|
|
|
AppendStringToBuffer(Output, Copy(SSpaces,1,Indent));
|
|
|
- ASNDebugItem(Buffer, Index, ASNType, ASNSize, Output);
|
|
|
+ ASNDebugItem(p, EndP, ASNType, ASNSize, Output);
|
|
|
if (ASNType and $20) > 0 then
|
|
|
begin
|
|
|
+ // sequence/set -> indent
|
|
|
Inc(Indent, 2);
|
|
|
- IndentList:=Concat(IndentList,[ASNSize+Index-1]);
|
|
|
+ IndentList:=Concat(IndentList,[ASNSize+integer(EndP-p)]);
|
|
|
end;
|
|
|
AppendStringToBuffer(Output, #13#10);
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-procedure ASNParseAdd(List: TStrings; const S: AnsiString; const ASNType, ASNSize: Integer);
|
|
|
+procedure ASNParseAdd(List: TStrings; const S: String; const ASNType, ASNSize: Integer);
|
|
|
begin
|
|
|
+ if ASNSize>high(word) then
|
|
|
+ raise Exception.Create('20220428160845');
|
|
|
+ if ASNType>high(word) then
|
|
|
+ raise Exception.Create('20220428160853');
|
|
|
List.AddObject(S, TObject(PtrInt (ASNType shl 16) or (ASNSize)));
|
|
|
end;
|
|
|
|
|
|
-procedure ASNParseAddInt(const Buffer: TBytes; var Start: Integer; List: TStrings; const ASNType, ASNSize: Integer);
|
|
|
+procedure ASNParseAddInt(var Buffer: PByte; BufferEnd: PByte; List: TStrings; const ASNType, ASNSize: Integer; Signed: boolean);
|
|
|
|
|
|
- procedure BufToString(var S : AnsiString);
|
|
|
+ procedure BufToString(var S : String);
|
|
|
|
|
|
begin
|
|
|
SetLength(S,ASNSize);
|
|
|
- if ASNSize>0 then
|
|
|
- Move(Buffer[Start],S[1],ASNSize);
|
|
|
- end;
|
|
|
-
|
|
|
-var
|
|
|
- S, S2: AnsiString;
|
|
|
- y: Int64;
|
|
|
-begin
|
|
|
- S:='';
|
|
|
- S2:='';
|
|
|
- if ASNSize < 8 then
|
|
|
- begin
|
|
|
- y := ASNParseInt(Buffer, Start, ASNSize);
|
|
|
- S:=IntToStr(y);
|
|
|
- end else
|
|
|
- begin
|
|
|
- BufToString(S2);
|
|
|
- if S2[1] = Char(#00) then
|
|
|
- Delete(S2,1,1);
|
|
|
- BytesToHexStr(S,TEncoding.UTF8.GetAnsiBytes(S2));
|
|
|
- Inc(Start, ASNSize);
|
|
|
+ if ASNSize=0 then exit;
|
|
|
+ Move(Buffer^,S[1],ASNSize);
|
|
|
+ inc(Buffer, ASNSize);
|
|
|
end;
|
|
|
- ASNParseAdd(List, S, ASNType, ASNSize);
|
|
|
-end;
|
|
|
-
|
|
|
-procedure ASNParseAddUInt(const Buffer: TBytes; var Start: Integer; List: TStrings; const ASNType, ASNSize: Integer);
|
|
|
-
|
|
|
- procedure BufToString(out S : AnsiString);
|
|
|
|
|
|
- begin
|
|
|
- S:='';
|
|
|
- SetLength(S,ASNSize);
|
|
|
- if ASNSize>0 then
|
|
|
- Move(Buffer[Start],S[1],ASNSize);
|
|
|
- end;
|
|
|
var
|
|
|
- S, S2: AnsiString;
|
|
|
+ S, S2: String;
|
|
|
y: Int64;
|
|
|
begin
|
|
|
S:='';
|
|
|
S2:='';
|
|
|
if ASNSize < 8 then
|
|
|
begin
|
|
|
- y := ASNParseUInt(Buffer, Start, ASNSize);
|
|
|
+ if Signed then
|
|
|
+ y := ASNParseInt(Buffer, BufferEnd, ASNSize)
|
|
|
+ else
|
|
|
+ y := ASNParseUInt(Buffer, BufferEnd, ASNSize);
|
|
|
S:=IntToStr(y);
|
|
|
end else
|
|
|
begin
|
|
@@ -672,27 +653,10 @@ begin
|
|
|
if S2[1] = Char(#00) then
|
|
|
Delete(S2,1,1);
|
|
|
BytesToHexStr(S,TEncoding.UTF8.GetAnsiBytes(S2));
|
|
|
- Inc(Start, ASNSize);
|
|
|
end;
|
|
|
ASNParseAdd(List, S, ASNType, ASNSize);
|
|
|
end;
|
|
|
|
|
|
-function ASNFetch(const Buffer: TBytes; var Offset: Int32; Out ASNType, ASNSize: Int32): Boolean;
|
|
|
-var
|
|
|
- Len: Int32;
|
|
|
-begin
|
|
|
- Result := False;
|
|
|
- Len := Length(Buffer);
|
|
|
- if Offset+2 > Len then
|
|
|
- Exit;
|
|
|
- ASNType := Buffer[Offset];
|
|
|
- Inc(Offset);
|
|
|
- ASNSize := ASNReadLen(Buffer, Offset);
|
|
|
- if (Offset + ASNSize) > Len then
|
|
|
- Exit;
|
|
|
- Result := True;
|
|
|
-end;
|
|
|
-
|
|
|
function ASNFetch(var Buffer: PByte; BufferEnd: PByte; out ASNType,
|
|
|
ASNSize: Int32): Boolean;
|
|
|
var
|
|
@@ -747,75 +711,77 @@ end;
|
|
|
// Beginning with the @Start position, decode the ASN.1 item of the next element in @Buffer. Type of item is stored in @ASNType
|
|
|
// @Offset starts at 0
|
|
|
|
|
|
-procedure ASNParseItem(const Buffer: TBytes; var Offset: Int32; List: TStrings);
|
|
|
-
|
|
|
- procedure BufToString(var S : AnsiString; P : PByte; Len : Integer);
|
|
|
+function ASNParseItem(var Buffer: PByte; BufferEnd: PByte; List: TStrings): boolean;
|
|
|
|
|
|
+ function BufToString(Len : Integer): String;
|
|
|
begin
|
|
|
- SetLength(S,Len);
|
|
|
- if Len>0 then
|
|
|
- Move(P^,S[1],Len);
|
|
|
+ SetLength(Result{%H-},Len);
|
|
|
+ if Len=0 then exit;
|
|
|
+ Move(Buffer^,Result[1],Len);
|
|
|
+ inc(Buffer, Len);
|
|
|
end;
|
|
|
|
|
|
var
|
|
|
ASNType, ASNSize: Integer;
|
|
|
n: Integer;
|
|
|
- S, S2: AnsiString;
|
|
|
+ S, S2: String;
|
|
|
y: Int64;
|
|
|
+ OldBuffer: PByte;
|
|
|
|
|
|
begin
|
|
|
- if not ASNFetch(Buffer, Offset, ASNType, ASNSize) then
|
|
|
+ Result:=false;
|
|
|
+ if not ASNFetch(Buffer, BufferEnd, ASNType, ASNSize) then
|
|
|
Exit;
|
|
|
if (ASNType and $20) > 0 then
|
|
|
begin // constructed
|
|
|
ASNParseAdd(List, '', ASNType, ASNSize);
|
|
|
Exit;
|
|
|
end;
|
|
|
+ if (BufferEnd-Buffer) < ASNSize then
|
|
|
+ Exit;
|
|
|
S:='';
|
|
|
S2:='';
|
|
|
case ASNType of
|
|
|
ASN1_INT, ASN1_ENUM, ASN1_BOOL:
|
|
|
begin
|
|
|
- ASNParseAddInt(Buffer, Offset, List, ASNType, ASNSize);
|
|
|
+ ASNParseAddInt(Buffer, BufferEnd, List, ASNType, ASNSize, true);
|
|
|
end;
|
|
|
ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS, ASN1_COUNTER64:
|
|
|
begin
|
|
|
- ASNParseAddUInt(Buffer, Offset, List, ASNType, ASNSize);
|
|
|
+ ASNParseAddInt(Buffer, BufferEnd, List, ASNType, ASNSize, false);
|
|
|
end;
|
|
|
ASN1_BITSTR, ASN1_OCTSTR, ASN1_OPAQUE:
|
|
|
begin
|
|
|
if ASNType = ASN1_BITSTR then
|
|
|
begin // this is the Trailing Length in bits
|
|
|
- Inc(Offset);
|
|
|
+ Inc(Buffer);
|
|
|
Dec(ASNSize);
|
|
|
end;
|
|
|
- BufToString(S2, @Buffer[Offset], ASNSize);
|
|
|
+ OldBuffer:=Buffer;
|
|
|
+ S2 := BufToString(ASNSize);
|
|
|
S:=BytesToHexStr(S2);
|
|
|
ASNParseAdd(List, S, ASNType, ASNSize);
|
|
|
- if (ASNType = ASN1_BITSTR) and (Buffer[Offset] = ASN1_SEQ) then
|
|
|
+ if (ASNType = ASN1_BITSTR) and (OldBuffer^ = ASN1_SEQ) then
|
|
|
begin
|
|
|
// continue to decode the bitstring as ASN.1 formatted content
|
|
|
- end else
|
|
|
- Inc(Offset, ASNSize);
|
|
|
+ Buffer:=OldBuffer;
|
|
|
+ end;
|
|
|
end;
|
|
|
ASN1_UTF8STRING, ASN1_PRINTABLESTRING, ASN1_IA5STRING:
|
|
|
begin
|
|
|
- BufToString(S2, @Buffer[Offset], ASNSize);
|
|
|
+ S2 := BufToString(ASNSize);
|
|
|
ASNParseAdd(List, S2, ASNType, ASNSize);
|
|
|
- Inc(Offset, ASNSize);
|
|
|
end;
|
|
|
ASN1_UTCTIME:
|
|
|
begin // 180131123456Z -> 2018-01-31 12:34:56
|
|
|
- BufToString(S2, @Buffer[Offset], ASNSize);
|
|
|
+ S2 := BufToString(ASNSize);
|
|
|
ASNParseAdd(List, S2, ASNType, ASNSize);
|
|
|
- Inc(Offset, ASNSize);
|
|
|
end;
|
|
|
ASN1_OBJID:
|
|
|
begin
|
|
|
- BufToString(S2, @Buffer[Offset], ASNSize);
|
|
|
+ S2 := BufToString(ASNSize);
|
|
|
IdToMib(S2, S);
|
|
|
ASNParseAdd(List, S, ASNType, ASNSize);
|
|
|
- Inc(Offset, ASNSize);
|
|
|
end;
|
|
|
ASN1_IPADDR:
|
|
|
begin
|
|
@@ -823,8 +789,8 @@ begin
|
|
|
begin
|
|
|
if n <> 1 then
|
|
|
S:=S+'.';
|
|
|
- y := Buffer[Offset];
|
|
|
- Inc(Offset);
|
|
|
+ y := Buffer^;
|
|
|
+ Inc(Buffer);
|
|
|
S:=S+IntToStr(y);
|
|
|
end;
|
|
|
ASNParseAdd(List, S, ASNType, ASNSize);
|
|
@@ -832,69 +798,50 @@ begin
|
|
|
ASN1_NULL:
|
|
|
begin
|
|
|
ASNParseAdd(List, '', ASNType, ASNSize);
|
|
|
- Inc(Offset, ASNSize);
|
|
|
+ Inc(Buffer, ASNSize);
|
|
|
end;
|
|
|
else // unknown
|
|
|
begin
|
|
|
- BufToString(S2, @Buffer[Offset], ASNSize);
|
|
|
+ S2 := BufToString(ASNSize);
|
|
|
S:=BytesToHexStr(S2);
|
|
|
ASNParseAdd(List, S, ASNType, ASNSize);
|
|
|
- Inc(Offset, ASNSize);
|
|
|
end;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-// Convert ASN.1 DER encoded buffer to human readable form for debugging
|
|
|
procedure ASNParse(const Buffer: TBytes; List: TStrings);
|
|
|
var
|
|
|
- Index: integer;
|
|
|
-begin
|
|
|
- Index := 0;
|
|
|
- while Index < Length(Buffer) do
|
|
|
- ASNParseItem(Buffer, Index, List);
|
|
|
-end;
|
|
|
-
|
|
|
-procedure PemToDER(PEM: TBytes; const BeginTag, EndTag: AnsiString; out DER: TBytes);
|
|
|
-
|
|
|
+ P, EndP: PByte;
|
|
|
begin
|
|
|
- PemToDER(TEncoding.UTF8.GetAnsiString(PEM),BeginTag,EndTag,DER);
|
|
|
+ if length(Buffer)=0 then exit;
|
|
|
+ P:=@Buffer[0];
|
|
|
+ EndP:=P+length(Buffer);
|
|
|
+ while P < EndP do
|
|
|
+ ASNParseItem(p, EndP, List);
|
|
|
end;
|
|
|
|
|
|
-procedure PemToDER(Const PEM: AnsiString; const BeginTag, EndTag: AnsiString; Out DER: TBytes);
|
|
|
-
|
|
|
+procedure ASNParse_GetItem(List: TStrings; Index: integer; out ASNType,
|
|
|
+ ASNSize: integer);
|
|
|
var
|
|
|
- Content: AnsiString;
|
|
|
-
|
|
|
+ h: PtrUInt;
|
|
|
begin
|
|
|
- DER:=[];
|
|
|
- Content:=ExtractBetween(Pem, BeginTag, EndTag);
|
|
|
- Content:=Trim(Content);
|
|
|
- if Length(Content) = 0 then
|
|
|
- Exit;
|
|
|
- DER:=Base64.Decode(Content,True);
|
|
|
-end;
|
|
|
-
|
|
|
-procedure ASNParsePemSection(const PEM: TBytes; List: TStrings; const BeginTag, EndTag: AnsiString);
|
|
|
-
|
|
|
-begin
|
|
|
- ASNParsePemSection(TEncoding.UTF8.GetAnsiString(PEM),List,BeginTag,EndTag);
|
|
|
+ h:=PtrUInt(List.Objects[Index]);
|
|
|
+ ASNType:=h shr 16;
|
|
|
+ ASNSize:=h and $ffff;
|
|
|
end;
|
|
|
|
|
|
-procedure ASNParsePemSection(const PEM: AnsiString; List: TStrings; const BeginTag, EndTag: AnsiString);
|
|
|
-
|
|
|
+function ASNParse_GetIntBytes(List: TStrings; ListIndex: integer; ID: int64
|
|
|
+ ): TBytes;
|
|
|
var
|
|
|
- BufferSection: TBytes;
|
|
|
-// S : AnsiString;
|
|
|
-
|
|
|
+ ASNType, ASNSize: Integer;
|
|
|
begin
|
|
|
- List.Clear;
|
|
|
- PemToDER(PEM, BeginTag, EndTag, BufferSection);
|
|
|
- {ASNDebug(BufferSection,Res);
|
|
|
- S:=TEncoding.UTF8.GetAnsiString(Res);
|
|
|
- Writeln('ASN Debug: ',S);}
|
|
|
- ASNParse(BufferSection, List);
|
|
|
+ ASNParse_GetItem(List,ListIndex,ASNType,ASNSize);
|
|
|
+ if ASNType<>ASN1_INT then
|
|
|
+ raise Exception.Create(IntToStr(Id));
|
|
|
+ Result:=HexStrToBytes(List[ListIndex]);
|
|
|
+ if length(Result)<1 then
|
|
|
+ raise Exception.Create(IntToStr(Id));
|
|
|
end;
|
|
|
|
|
|
-
|
|
|
end.
|
|
|
|