source: trunk/Demo/Packages/synapse/asn1util.pas

Last change on this file was 60, checked in by chronos, 12 years ago
File size: 14.9 KB
Line 
1{==============================================================================|
2| Project : Ararat Synapse | 001.004.004 |
3|==============================================================================|
4| Content: support for ASN.1 BER coding and decoding |
5|==============================================================================|
6| Copyright (c)1999-2003, Lukas Gebauer |
7| All rights reserved. |
8| |
9| Redistribution and use in source and binary forms, with or without |
10| modification, are permitted provided that the following conditions are met: |
11| |
12| Redistributions of source code must retain the above copyright notice, this |
13| list of conditions and the following disclaimer. |
14| |
15| Redistributions in binary form must reproduce the above copyright notice, |
16| this list of conditions and the following disclaimer in the documentation |
17| and/or other materials provided with the distribution. |
18| |
19| Neither the name of Lukas Gebauer nor the names of its contributors may |
20| be used to endorse or promote products derived from this software without |
21| specific prior written permission. |
22| |
23| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
27| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
29| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
33| DAMAGE. |
34|==============================================================================|
35| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
36| Portions created by Lukas Gebauer are Copyright (c) 1999-2003 |
37| Portions created by Hernan Sanchez are Copyright (c) 2000. |
38| All Rights Reserved. |
39|==============================================================================|
40| Contributor(s): |
41| Hernan Sanchez (hernan.sanchez@iname.com) |
42|==============================================================================|
43| History: see HISTORY.HTM from distribution package |
44| (Found at URL: http://www.ararat.cz/synapse/) |
45|==============================================================================}
46
47{: @abstract(Utilities for handling ASN.1 BER encoding)
48By this unit you can parse ASN.1 BER encoded data to elements or build back any
49 elements to ASN.1 BER encoded buffer. You can dump ASN.1 BER encoded data to
50 human readable form for easy debugging, too.
51
52Supported element types are: ASN1_BOOL, ASN1_INT, ASN1_OCTSTR, ASN1_NULL,
53 ASN1_OBJID, ASN1_ENUM, ASN1_SEQ, ASN1_SETOF, ASN1_IPADDR, ASN1_COUNTER,
54 ASN1_GAUGE, ASN1_TIMETICKS, ASN1_OPAQUE
55
56For sample of using, look to @link(TSnmpSend) or @link(TLdapSend)class.
57}
58
59{$Q-}
60{$H+}
61{$IFDEF FPC}
62 {$MODE DELPHI}
63{$ENDIF}
64
65unit asn1util;
66
67interface
68
69uses
70 SysUtils, Classes, synautil;
71
72const
73 ASN1_BOOL = $01;
74 ASN1_INT = $02;
75 ASN1_OCTSTR = $04;
76 ASN1_NULL = $05;
77 ASN1_OBJID = $06;
78 ASN1_ENUM = $0a;
79 ASN1_SEQ = $30;
80 ASN1_SETOF = $31;
81 ASN1_IPADDR = $40;
82 ASN1_COUNTER = $41;
83 ASN1_GAUGE = $42;
84 ASN1_TIMETICKS = $43;
85 ASN1_OPAQUE = $44;
86
87{:Encodes OID item to binary form.}
88function ASNEncOIDItem(Value: Integer): AnsiString;
89
90{:Decodes an OID item of the next element in the "Buffer" from the "Start"
91 position.}
92function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Integer;
93
94{:Encodes the length of ASN.1 element to binary.}
95function ASNEncLen(Len: Integer): AnsiString;
96
97{:Decodes length of next element in "Buffer" from the "Start" position.}
98function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
99
100{:Encodes a signed integer to ASN.1 binary}
101function ASNEncInt(Value: Integer): AnsiString;
102
103{:Encodes unsigned integer into ASN.1 binary}
104function ASNEncUInt(Value: Integer): AnsiString;
105
106{:Encodes ASN.1 object to binary form.}
107function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
108
109{:Beginning with the "Start" position, decode the ASN.1 item of the next element
110 in "Buffer". Type of item is stored in "ValueType."}
111function ASNItem(var Start: Integer; const Buffer: AnsiString;
112 var ValueType: Integer): AnsiString;
113
114{:Encodes an MIB OID string to binary form.}
115function MibToId(Mib: String): AnsiString;
116
117{:Decodes MIB OID from binary form to string form.}
118function IdToMib(const Id: AnsiString): String;
119
120{:Encodes an one number from MIB OID to binary form. (used internally from
121@link(MibToId))}
122function IntMibToStr(const Value: AnsiString): AnsiString;
123
124{:Convert ASN.1 BER encoded buffer to human readable form for debugging.}
125function ASNdump(const Value: AnsiString): AnsiString;
126
127implementation
128
129{==============================================================================}
130function ASNEncOIDItem(Value: Integer): AnsiString;
131var
132 x, xm: Integer;
133 b: Boolean;
134begin
135 x := Value;
136 b := False;
137 Result := '';
138 repeat
139 xm := x mod 128;
140 x := x div 128;
141 if b then
142 xm := xm or $80;
143 if x > 0 then
144 b := True;
145 Result := AnsiChar(xm) + Result;
146 until x = 0;
147end;
148
149{==============================================================================}
150function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Integer;
151var
152 x: Integer;
153 b: Boolean;
154begin
155 Result := 0;
156 repeat
157 Result := Result * 128;
158 x := Ord(Buffer[Start]);
159 Inc(Start);
160 b := x > $7F;
161 x := x and $7F;
162 Result := Result + x;
163 until not b;
164end;
165
166{==============================================================================}
167function ASNEncLen(Len: Integer): AnsiString;
168var
169 x, y: Integer;
170begin
171 if Len < $80 then
172 Result := AnsiChar(Len)
173 else
174 begin
175 x := Len;
176 Result := '';
177 repeat
178 y := x mod 256;
179 x := x div 256;
180 Result := AnsiChar(y) + Result;
181 until x = 0;
182 y := Length(Result);
183 y := y or $80;
184 Result := AnsiChar(y) + Result;
185 end;
186end;
187
188{==============================================================================}
189function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
190var
191 x, n: Integer;
192begin
193 x := Ord(Buffer[Start]);
194 Inc(Start);
195 if x < $80 then
196 Result := x
197 else
198 begin
199 Result := 0;
200 x := x and $7F;
201 for n := 1 to x do
202 begin
203 Result := Result * 256;
204 x := Ord(Buffer[Start]);
205 Inc(Start);
206 Result := Result + x;
207 end;
208 end;
209end;
210
211{==============================================================================}
212function ASNEncInt(Value: Integer): AnsiString;
213var
214 x, y: Cardinal;
215 neg: Boolean;
216begin
217 neg := Value < 0;
218 x := Abs(Value);
219 if neg then
220 x := not (x - 1);
221 Result := '';
222 repeat
223 y := x mod 256;
224 x := x div 256;
225 Result := AnsiChar(y) + Result;
226 until x = 0;
227 if (not neg) and (Result[1] > #$7F) then
228 Result := #0 + Result;
229end;
230
231{==============================================================================}
232function ASNEncUInt(Value: Integer): AnsiString;
233var
234 x, y: Integer;
235 neg: Boolean;
236begin
237 neg := Value < 0;
238 x := Value;
239 if neg then
240 x := x and $7FFFFFFF;
241 Result := '';
242 repeat
243 y := x mod 256;
244 x := x div 256;
245 Result := AnsiChar(y) + Result;
246 until x = 0;
247 if neg then
248 Result[1] := AnsiChar(Ord(Result[1]) or $80);
249end;
250
251{==============================================================================}
252function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
253begin
254 Result := AnsiChar(ASNType) + ASNEncLen(Length(Data)) + Data;
255end;
256
257{==============================================================================}
258function ASNItem(var Start: Integer; const Buffer: AnsiString;
259 var ValueType: Integer): AnsiString;
260var
261 ASNType: Integer;
262 ASNSize: Integer;
263 y, n: Integer;
264 x: byte;
265 s: AnsiString;
266 c: AnsiChar;
267 neg: Boolean;
268 l: Integer;
269begin
270 Result := '';
271 ValueType := ASN1_NULL;
272 l := Length(Buffer);
273 if l < (Start + 1) then
274 Exit;
275 ASNType := Ord(Buffer[Start]);
276 ValueType := ASNType;
277 Inc(Start);
278 ASNSize := ASNDecLen(Start, Buffer);
279 if (Start + ASNSize - 1) > l then
280 Exit;
281 if (ASNType and $20) > 0 then
282// Result := '$' + IntToHex(ASNType, 2)
283 Result := Copy(Buffer, Start, ASNSize)
284 else
285 case ASNType of
286 ASN1_INT, ASN1_ENUM, ASN1_BOOL:
287 begin
288 y := 0;
289 neg := False;
290 for n := 1 to ASNSize do
291 begin
292 x := Ord(Buffer[Start]);
293 if (n = 1) and (x > $7F) then
294 neg := True;
295 if neg then
296 x := not x;
297 y := y * 256 + x;
298 Inc(Start);
299 end;
300 if neg then
301 y := -(y + 1);
302 Result := IntToStr(y);
303 end;
304 ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS:
305 begin
306 y := 0;
307 for n := 1 to ASNSize do
308 begin
309 y := y * 256 + Ord(Buffer[Start]);
310 Inc(Start);
311 end;
312 Result := IntToStr(y);
313 end;
314 ASN1_OCTSTR, ASN1_OPAQUE:
315 begin
316 for n := 1 to ASNSize do
317 begin
318 c := AnsiChar(Buffer[Start]);
319 Inc(Start);
320 s := s + c;
321 end;
322 Result := s;
323 end;
324 ASN1_OBJID:
325 begin
326 for n := 1 to ASNSize do
327 begin
328 c := AnsiChar(Buffer[Start]);
329 Inc(Start);
330 s := s + c;
331 end;
332 Result := IdToMib(s);
333 end;
334 ASN1_IPADDR:
335 begin
336 s := '';
337 for n := 1 to ASNSize do
338 begin
339 if (n <> 1) then
340 s := s + '.';
341 y := Ord(Buffer[Start]);
342 Inc(Start);
343 s := s + IntToStr(y);
344 end;
345 Result := s;
346 end;
347 ASN1_NULL:
348 begin
349 Result := '';
350 Start := Start + ASNSize;
351 end;
352 else // unknown
353 begin
354 for n := 1 to ASNSize do
355 begin
356 c := AnsiChar(Buffer[Start]);
357 Inc(Start);
358 s := s + c;
359 end;
360 Result := s;
361 end;
362 end;
363end;
364
365{==============================================================================}
366function MibToId(Mib: String): AnsiString;
367var
368 x: Integer;
369
370 function WalkInt(var s: String): Integer;
371 var
372 x: Integer;
373 t: AnsiString;
374 begin
375 x := Pos('.', s);
376 if x < 1 then
377 begin
378 t := s;
379 s := '';
380 end
381 else
382 begin
383 t := Copy(s, 1, x - 1);
384 s := Copy(s, x + 1, Length(s) - x);
385 end;
386 Result := StrToIntDef(t, 0);
387 end;
388
389begin
390 Result := '';
391 x := WalkInt(Mib);
392 x := x * 40 + WalkInt(Mib);
393 Result := ASNEncOIDItem(x);
394 while Mib <> '' do
395 begin
396 x := WalkInt(Mib);
397 Result := Result + ASNEncOIDItem(x);
398 end;
399end;
400
401{==============================================================================}
402function IdToMib(const Id: AnsiString): String;
403var
404 x, y, n: Integer;
405begin
406 Result := '';
407 n := 1;
408 while Length(Id) + 1 > n do
409 begin
410 x := ASNDecOIDItem(n, Id);
411 if (n - 1) = 1 then
412 begin
413 y := x div 40;
414 x := x mod 40;
415 Result := IntToStr(y);
416 end;
417 Result := Result + '.' + IntToStr(x);
418 end;
419end;
420
421{==============================================================================}
422function IntMibToStr(const Value: AnsiString): AnsiString;
423var
424 n, y: Integer;
425begin
426 y := 0;
427 for n := 1 to Length(Value) - 1 do
428 y := y * 256 + Ord(Value[n]);
429 Result := IntToStr(y);
430end;
431
432{==============================================================================}
433function ASNdump(const Value: AnsiString): AnsiString;
434var
435 i, at, x, n: integer;
436 s, indent: AnsiString;
437 il: TStringList;
438begin
439 il := TStringList.Create;
440 try
441 Result := '';
442 i := 1;
443 indent := '';
444 while i < Length(Value) do
445 begin
446 for n := il.Count - 1 downto 0 do
447 begin
448 x := StrToIntDef(il[n], 0);
449 if x <= i then
450 begin
451 il.Delete(n);
452 Delete(indent, 1, 2);
453 end;
454 end;
455 s := ASNItem(i, Value, at);
456 Result := Result + indent + '$' + IntToHex(at, 2);
457 if (at and $20) > 0 then
458 begin
459 x := Length(s);
460 Result := Result + ' constructed: length ' + IntToStr(x);
461 indent := indent + ' ';
462 il.Add(IntToStr(x + i - 1));
463 end
464 else
465 begin
466 case at of
467 ASN1_BOOL:
468 Result := Result + ' BOOL: ';
469 ASN1_INT:
470 Result := Result + ' INT: ';
471 ASN1_ENUM:
472 Result := Result + ' ENUM: ';
473 ASN1_COUNTER:
474 Result := Result + ' COUNTER: ';
475 ASN1_GAUGE:
476 Result := Result + ' GAUGE: ';
477 ASN1_TIMETICKS:
478 Result := Result + ' TIMETICKS: ';
479 ASN1_OCTSTR:
480 Result := Result + ' OCTSTR: ';
481 ASN1_OPAQUE:
482 Result := Result + ' OPAQUE: ';
483 ASN1_OBJID:
484 Result := Result + ' OBJID: ';
485 ASN1_IPADDR:
486 Result := Result + ' IPADDR: ';
487 ASN1_NULL:
488 Result := Result + ' NULL: ';
489 else // other
490 Result := Result + ' unknown: ';
491 end;
492 if IsBinaryString(s) then
493 s := DumpExStr(s);
494 Result := Result + s;
495 end;
496 Result := Result + #$0d + #$0a;
497 end;
498 finally
499 il.Free;
500 end;
501end;
502
503{==============================================================================}
504
505end.
Note: See TracBrowser for help on using the repository browser.