123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- {==============================================================================|
- | Project : Ararat Synapse | 002.001.001 |
- |==============================================================================|
- | Content: support for ASN.1 BER coding and decoding |
- |==============================================================================|
- | Copyright (c)1999-2021, Lukas Gebauer |
- | All rights reserved. |
- | |
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the following conditions are met: |
- | |
- | Redistributions of source code must retain the above copyright notice, this |
- | list of conditions and the following disclaimer. |
- | |
- | Redistributions in binary form must reproduce the above copyright notice, |
- | this list of conditions and the following disclaimer in the documentation |
- | and/or other materials provided with the distribution. |
- | |
- | Neither the name of Lukas Gebauer nor the names of its contributors may |
- | be used to endorse or promote products derived from this software without |
- | specific prior written permission. |
- | |
- | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
- | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
- | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
- | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
- | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
- | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
- | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
- | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
- | DAMAGE. |
- |==============================================================================|
- | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
- | Portions created by Lukas Gebauer are Copyright (c) 1999-2021 |
- | Portions created by Hernan Sanchez are Copyright (c) 2000. |
- | All Rights Reserved. |
- |==============================================================================|
- | Contributor(s): |
- | Hernan Sanchez ([email protected]) |
- |==============================================================================|
- | History: see HISTORY.HTM from distribution package |
- | (Found at URL: http://www.ararat.cz/synapse/) |
- |==============================================================================}
- {: @abstract(Utilities for handling ASN.1 BER encoding)
- By this unit you can parse ASN.1 BER encoded data to elements or build back any
- elements to ASN.1 BER encoded buffer. You can dump ASN.1 BER encoded data to
- human readable form for easy debugging, too.
- Supported element types are: ASN1_BOOL, ASN1_INT, ASN1_OCTSTR, ASN1_NULL,
- ASN1_OBJID, ASN1_ENUM, ASN1_SEQ, ASN1_SETOF, ASN1_IPADDR, ASN1_COUNTER,
- ASN1_GAUGE, ASN1_TIMETICKS, ASN1_OPAQUE
- For sample of using, look to @link(TSnmpSend) or @link(TLdapSend)class.
- }
- {$Q-}
- {$H+}
- {$IFDEF FPC}
- {$MODE DELPHI}
- {$ENDIF}
- {$IFDEF UNICODE}
- {$WARN IMPLICIT_STRING_CAST OFF}
- {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
- {$ENDIF}
- unit asn1util;
- interface
- uses
- SysUtils, Classes, synautil;
- const
- ASN1_BOOL = $01;
- ASN1_INT = $02;
- ASN1_OCTSTR = $04;
- ASN1_NULL = $05;
- ASN1_OBJID = $06;
- ASN1_ENUM = $0a;
- ASN1_SEQ = $30;
- ASN1_SETOF = $31;
- ASN1_IPADDR = $40;
- ASN1_COUNTER = $41;
- ASN1_GAUGE = $42;
- ASN1_TIMETICKS = $43;
- ASN1_OPAQUE = $44;
- ASN1_COUNTER64 = $46;
- {:Encodes OID item to binary form.}
- function ASNEncOIDItem(Value: Int64): AnsiString;
- {:Decodes an OID item of the next element in the "Buffer" from the "Start"
- position.}
- function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Int64;
- {:Encodes the length of ASN.1 element to binary.}
- function ASNEncLen(Len: Integer): AnsiString;
- {:Decodes length of next element in "Buffer" from the "Start" position.}
- function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
- {:Encodes a signed integer to ASN.1 binary}
- function ASNEncInt(Value: Int64): AnsiString;
- {:Encodes unsigned integer into ASN.1 binary}
- function ASNEncUInt(Value: Integer): AnsiString;
- {:Encodes ASN.1 object to binary form.}
- function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
- {:Beginning with the "Start" position, decode the ASN.1 item of the next element
- in "Buffer". Type of item is stored in "ValueType."}
- function ASNItem(var Start: Integer; const Buffer: AnsiString;
- var ValueType: Integer): AnsiString;
- {:Encodes an MIB OID string to binary form.}
- function MibToId(Mib: String): AnsiString;
- {:Decodes MIB OID from binary form to string form.}
- function IdToMib(const Id: AnsiString): String;
- {:Encodes an one number from MIB OID to binary form. (used internally from
- @link(MibToId))}
- function IntMibToStr(const Value: AnsiString): AnsiString;
- {:Convert ASN.1 BER encoded buffer to human readable form for debugging.}
- function ASNdump(const Value: AnsiString): AnsiString;
- implementation
- {==============================================================================}
- function ASNEncOIDItem(Value: Int64): AnsiString;
- var
- x: Int64;
- xm: Byte;
- b: Boolean;
- begin
- x := Value;
- b := False;
- Result := '';
- repeat
- xm := x mod 128;
- x := x div 128;
- if b then
- xm := xm or $80;
- if x > 0 then
- b := True;
- Result := AnsiChar(xm) + Result;
- until x = 0;
- end;
- {==============================================================================}
- function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Int64;
- var
- x: Integer;
- b: Boolean;
- begin
- Result := 0;
- repeat
- Result := Result * 128;
- x := Ord(Buffer[Start]);
- Inc(Start);
- b := x > $7F;
- x := x and $7F;
- Result := Result + x;
- until not b;
- end;
- {==============================================================================}
- function ASNEncLen(Len: Integer): AnsiString;
- var
- x, y: Integer;
- begin
- if Len < $80 then
- Result := AnsiChar(Len)
- else
- begin
- x := Len;
- Result := '';
- repeat
- y := x mod 256;
- x := x div 256;
- Result := AnsiChar(y) + Result;
- until x = 0;
- y := Length(Result);
- y := y or $80;
- Result := AnsiChar(y) + Result;
- end;
- end;
- {==============================================================================}
- function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
- var
- x, n: Integer;
- begin
- x := Ord(Buffer[Start]);
- Inc(Start);
- if x < $80 then
- Result := x
- else
- begin
- Result := 0;
- x := x and $7F;
- for n := 1 to x do
- begin
- Result := Result * 256;
- x := Ord(Buffer[Start]);
- Inc(Start);
- Result := Result + x;
- end;
- end;
- end;
- {==============================================================================}
- function ASNEncInt(Value: Int64): AnsiString;
- var
- x: Int64;
- y: byte;
- neg: Boolean;
- begin
- neg := Value < 0;
- x := Abs(Value);
- if neg then
- x := x - 1;
- Result := '';
- repeat
- y := x mod 256;
- x := x div 256;
- if neg then
- y := not y;
- Result := AnsiChar(y) + Result;
- until x = 0;
- if (not neg) and (Result[1] > #$7F) then
- Result := #0 + Result;
- if (neg) and (Result[1] < #$80) then
- Result := #$FF + Result;
- end;
- {==============================================================================}
- function ASNEncUInt(Value: Integer): AnsiString;
- var
- x, y: Integer;
- neg: Boolean;
- begin
- neg := Value < 0;
- x := Value;
- if neg then
- x := x and $7FFFFFFF;
- Result := '';
- repeat
- y := x mod 256;
- x := x div 256;
- Result := AnsiChar(y) + Result;
- until x = 0;
- if neg then
- Result[1] := AnsiChar(Ord(Result[1]) or $80);
- end;
- {==============================================================================}
- function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
- begin
- Result := AnsiChar(ASNType) + ASNEncLen(Length(Data)) + Data;
- end;
- {==============================================================================}
- function ASNItem(var Start: Integer; const Buffer: AnsiString;
- var ValueType: Integer): AnsiString;
- var
- ASNType: Integer;
- ASNSize: Integer;
- y: int64;
- n: Integer;
- x: byte;
- s: AnsiString;
- c: AnsiChar;
- neg: Boolean;
- l: Integer;
- begin
- Result := '';
- ValueType := ASN1_NULL;
- l := Length(Buffer);
- if l < (Start + 1) then
- Exit;
- s := '';
- ASNType := Ord(Buffer[Start]);
- ValueType := ASNType;
- Inc(Start);
- ASNSize := ASNDecLen(Start, Buffer);
- if (Start + ASNSize - 1) > l then
- Exit;
- if (ASNType and $20) > 0 then
- // Result := '$' + IntToHex(ASNType, 2)
- Result := Copy(Buffer, Start, ASNSize)
- else
- case ASNType of
- ASN1_INT, ASN1_ENUM, ASN1_BOOL:
- begin
- y := 0;
- neg := False;
- for n := 1 to ASNSize do
- begin
- x := Ord(Buffer[Start]);
- if (n = 1) and (x > $7F) then
- neg := True;
- if neg then
- x := not x;
- y := y * 256 + x;
- Inc(Start);
- end;
- if neg then
- y := -(y + 1);
- Result := IntToStr(y);
- end;
- ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS, ASN1_COUNTER64:
- begin
- y := 0;
- for n := 1 to ASNSize do
- begin
- y := y * 256 + Ord(Buffer[Start]);
- Inc(Start);
- end;
- Result := IntToStr(y);
- end;
- ASN1_OCTSTR, ASN1_OPAQUE:
- begin
- for n := 1 to ASNSize do
- begin
- c := AnsiChar(Buffer[Start]);
- Inc(Start);
- s := s + c;
- end;
- Result := s;
- end;
- ASN1_OBJID:
- begin
- for n := 1 to ASNSize do
- begin
- c := AnsiChar(Buffer[Start]);
- Inc(Start);
- s := s + c;
- end;
- Result := IdToMib(s);
- end;
- ASN1_IPADDR:
- begin
- s := '';
- for n := 1 to ASNSize do
- begin
- if (n <> 1) then
- s := s + '.';
- y := Ord(Buffer[Start]);
- Inc(Start);
- s := s + IntToStr(y);
- end;
- Result := s;
- end;
- ASN1_NULL:
- begin
- Result := '';
- Start := Start + ASNSize;
- end;
- else // unknown
- begin
- for n := 1 to ASNSize do
- begin
- c := AnsiChar(Buffer[Start]);
- Inc(Start);
- s := s + c;
- end;
- Result := s;
- end;
- end;
- end;
- {==============================================================================}
- function MibToId(Mib: String): AnsiString;
- var
- x: int64;
- function WalkInt(var s: String): int64;
- var
- x: Integer;
- t: AnsiString;
- begin
- x := Pos('.', s);
- if x < 1 then
- begin
- t := s;
- s := '';
- end
- else
- begin
- t := Copy(s, 1, x - 1);
- s := Copy(s, x + 1, Length(s) - x);
- end;
- Result := StrToInt64Def(t, 0);
- end;
- begin
- Result := '';
- x := WalkInt(Mib);
- x := x * 40 + WalkInt(Mib);
- Result := ASNEncOIDItem(x);
- while Mib <> '' do
- begin
- x := WalkInt(Mib);
- Result := Result + ASNEncOIDItem(x);
- end;
- end;
- {==============================================================================}
- function IdToMib(const Id: AnsiString): String;
- var
- x, y: int64;
- n: Integer;
- begin
- Result := '';
- n := 1;
- while Length(Id) + 1 > n do
- begin
- x := ASNDecOIDItem(n, Id);
- if (n - 1) = 1 then
- begin
- y := x div 40;
- x := x mod 40;
- Result := IntToStr(y);
- end;
- Result := Result + '.' + IntToStr(x);
- end;
- end;
- {==============================================================================}
- function IntMibToStr(const Value: AnsiString): AnsiString;
- var
- n, y: Integer;
- begin
- y := 0;
- for n := 1 to Length(Value) - 1 do
- y := y * 256 + Ord(Value[n]);
- Result := IntToStr(y);
- end;
- {==============================================================================}
- function ASNdump(const Value: AnsiString): AnsiString;
- var
- i, at, x, n: integer;
- s, indent: AnsiString;
- il: TStringList;
- begin
- il := TStringList.Create;
- try
- Result := '';
- i := 1;
- indent := '';
- while i < Length(Value) do
- begin
- for n := il.Count - 1 downto 0 do
- begin
- x := StrToIntDef(il[n], 0);
- if x <= i then
- begin
- il.Delete(n);
- Delete(indent, 1, 2);
- end;
- end;
- s := ASNItem(i, Value, at);
- Result := Result + indent + '$' + IntToHex(at, 2);
- if (at and $20) > 0 then
- begin
- x := Length(s);
- Result := Result + ' constructed: length ' + IntToStr(x);
- indent := indent + ' ';
- il.Add(IntToStr(x + i - 1));
- end
- else
- begin
- case at of
- ASN1_BOOL:
- Result := Result + ' BOOL: ';
- ASN1_INT:
- Result := Result + ' INT: ';
- ASN1_ENUM:
- Result := Result + ' ENUM: ';
- ASN1_COUNTER:
- Result := Result + ' COUNTER: ';
- ASN1_GAUGE:
- Result := Result + ' GAUGE: ';
- ASN1_TIMETICKS:
- Result := Result + ' TIMETICKS: ';
- ASN1_OCTSTR:
- Result := Result + ' OCTSTR: ';
- ASN1_OPAQUE:
- Result := Result + ' OPAQUE: ';
- ASN1_OBJID:
- Result := Result + ' OBJID: ';
- ASN1_IPADDR:
- Result := Result + ' IPADDR: ';
- ASN1_NULL:
- Result := Result + ' NULL: ';
- ASN1_COUNTER64:
- Result := Result + ' COUNTER64: ';
- else // other
- Result := Result + ' unknown: ';
- end;
- if IsBinaryString(s) then
- s := DumpExStr(s);
- Result := Result + s;
- end;
- Result := Result + #$0d + #$0a;
- end;
- finally
- il.Free;
- end;
- end;
- {==============================================================================}
- end.
|