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

Last change on this file was 2, checked in by chronos, 12 years ago
  • Přidáno: Základní kostra projektu.
  • Přidáno: Knihovna synapse.
File size: 15.0 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
65{$IFDEF UNICODE}
66 {$WARN IMPLICIT_STRING_CAST OFF}
67 {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
68{$ENDIF}
69
70unit asn1util;
71
72interface
73
74uses
75 SysUtils, Classes, synautil;
76
77const
78 ASN1_BOOL = $01;
79 ASN1_INT = $02;
80 ASN1_OCTSTR = $04;
81 ASN1_NULL = $05;
82 ASN1_OBJID = $06;
83 ASN1_ENUM = $0a;
84 ASN1_SEQ = $30;
85 ASN1_SETOF = $31;
86 ASN1_IPADDR = $40;
87 ASN1_COUNTER = $41;
88 ASN1_GAUGE = $42;
89 ASN1_TIMETICKS = $43;
90 ASN1_OPAQUE = $44;
91
92{:Encodes OID item to binary form.}
93function ASNEncOIDItem(Value: Integer): AnsiString;
94
95{:Decodes an OID item of the next element in the "Buffer" from the "Start"
96 position.}
97function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Integer;
98
99{:Encodes the length of ASN.1 element to binary.}
100function ASNEncLen(Len: Integer): AnsiString;
101
102{:Decodes length of next element in "Buffer" from the "Start" position.}
103function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
104
105{:Encodes a signed integer to ASN.1 binary}
106function ASNEncInt(Value: Integer): AnsiString;
107
108{:Encodes unsigned integer into ASN.1 binary}
109function ASNEncUInt(Value: Integer): AnsiString;
110
111{:Encodes ASN.1 object to binary form.}
112function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
113
114{:Beginning with the "Start" position, decode the ASN.1 item of the next element
115 in "Buffer". Type of item is stored in "ValueType."}
116function ASNItem(var Start: Integer; const Buffer: AnsiString;
117 var ValueType: Integer): AnsiString;
118
119{:Encodes an MIB OID string to binary form.}
120function MibToId(Mib: String): AnsiString;
121
122{:Decodes MIB OID from binary form to string form.}
123function IdToMib(const Id: AnsiString): String;
124
125{:Encodes an one number from MIB OID to binary form. (used internally from
126@link(MibToId))}
127function IntMibToStr(const Value: AnsiString): AnsiString;
128
129{:Convert ASN.1 BER encoded buffer to human readable form for debugging.}
130function ASNdump(const Value: AnsiString): AnsiString;
131
132implementation
133
134{==============================================================================}
135function ASNEncOIDItem(Value: Integer): AnsiString;
136var
137 x, xm: Integer;
138 b: Boolean;
139begin
140 x := Value;
141 b := False;
142 Result := '';
143 repeat
144 xm := x mod 128;
145 x := x div 128;
146 if b then
147 xm := xm or $80;
148 if x > 0 then
149 b := True;
150 Result := AnsiChar(xm) + Result;
151 until x = 0;
152end;
153
154{==============================================================================}
155function ASNDecOIDItem(var Start: Integer; const Buffer: AnsiString): Integer;
156var
157 x: Integer;
158 b: Boolean;
159begin
160 Result := 0;
161 repeat
162 Result := Result * 128;
163 x := Ord(Buffer[Start]);
164 Inc(Start);
165 b := x > $7F;
166 x := x and $7F;
167 Result := Result + x;
168 until not b;
169end;
170
171{==============================================================================}
172function ASNEncLen(Len: Integer): AnsiString;
173var
174 x, y: Integer;
175begin
176 if Len < $80 then
177 Result := AnsiChar(Len)
178 else
179 begin
180 x := Len;
181 Result := '';
182 repeat
183 y := x mod 256;
184 x := x div 256;
185 Result := AnsiChar(y) + Result;
186 until x = 0;
187 y := Length(Result);
188 y := y or $80;
189 Result := AnsiChar(y) + Result;
190 end;
191end;
192
193{==============================================================================}
194function ASNDecLen(var Start: Integer; const Buffer: AnsiString): Integer;
195var
196 x, n: Integer;
197begin
198 x := Ord(Buffer[Start]);
199 Inc(Start);
200 if x < $80 then
201 Result := x
202 else
203 begin
204 Result := 0;
205 x := x and $7F;
206 for n := 1 to x do
207 begin
208 Result := Result * 256;
209 x := Ord(Buffer[Start]);
210 Inc(Start);
211 Result := Result + x;
212 end;
213 end;
214end;
215
216{==============================================================================}
217function ASNEncInt(Value: Integer): AnsiString;
218var
219 x, y: Cardinal;
220 neg: Boolean;
221begin
222 neg := Value < 0;
223 x := Abs(Value);
224 if neg then
225 x := not (x - 1);
226 Result := '';
227 repeat
228 y := x mod 256;
229 x := x div 256;
230 Result := AnsiChar(y) + Result;
231 until x = 0;
232 if (not neg) and (Result[1] > #$7F) then
233 Result := #0 + Result;
234end;
235
236{==============================================================================}
237function ASNEncUInt(Value: Integer): AnsiString;
238var
239 x, y: Integer;
240 neg: Boolean;
241begin
242 neg := Value < 0;
243 x := Value;
244 if neg then
245 x := x and $7FFFFFFF;
246 Result := '';
247 repeat
248 y := x mod 256;
249 x := x div 256;
250 Result := AnsiChar(y) + Result;
251 until x = 0;
252 if neg then
253 Result[1] := AnsiChar(Ord(Result[1]) or $80);
254end;
255
256{==============================================================================}
257function ASNObject(const Data: AnsiString; ASNType: Integer): AnsiString;
258begin
259 Result := AnsiChar(ASNType) + ASNEncLen(Length(Data)) + Data;
260end;
261
262{==============================================================================}
263function ASNItem(var Start: Integer; const Buffer: AnsiString;
264 var ValueType: Integer): AnsiString;
265var
266 ASNType: Integer;
267 ASNSize: Integer;
268 y, n: Integer;
269 x: byte;
270 s: AnsiString;
271 c: AnsiChar;
272 neg: Boolean;
273 l: Integer;
274begin
275 Result := '';
276 ValueType := ASN1_NULL;
277 l := Length(Buffer);
278 if l < (Start + 1) then
279 Exit;
280 ASNType := Ord(Buffer[Start]);
281 ValueType := ASNType;
282 Inc(Start);
283 ASNSize := ASNDecLen(Start, Buffer);
284 if (Start + ASNSize - 1) > l then
285 Exit;
286 if (ASNType and $20) > 0 then
287// Result := '$' + IntToHex(ASNType, 2)
288 Result := Copy(Buffer, Start, ASNSize)
289 else
290 case ASNType of
291 ASN1_INT, ASN1_ENUM, ASN1_BOOL:
292 begin
293 y := 0;
294 neg := False;
295 for n := 1 to ASNSize do
296 begin
297 x := Ord(Buffer[Start]);
298 if (n = 1) and (x > $7F) then
299 neg := True;
300 if neg then
301 x := not x;
302 y := y * 256 + x;
303 Inc(Start);
304 end;
305 if neg then
306 y := -(y + 1);
307 Result := IntToStr(y);
308 end;
309 ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS:
310 begin
311 y := 0;
312 for n := 1 to ASNSize do
313 begin
314 y := y * 256 + Ord(Buffer[Start]);
315 Inc(Start);
316 end;
317 Result := IntToStr(y);
318 end;
319 ASN1_OCTSTR, ASN1_OPAQUE:
320 begin
321 for n := 1 to ASNSize do
322 begin
323 c := AnsiChar(Buffer[Start]);
324 Inc(Start);
325 s := s + c;
326 end;
327 Result := s;
328 end;
329 ASN1_OBJID:
330 begin
331 for n := 1 to ASNSize do
332 begin
333 c := AnsiChar(Buffer[Start]);
334 Inc(Start);
335 s := s + c;
336 end;
337 Result := IdToMib(s);
338 end;
339 ASN1_IPADDR:
340 begin
341 s := '';
342 for n := 1 to ASNSize do
343 begin
344 if (n <> 1) then
345 s := s + '.';
346 y := Ord(Buffer[Start]);
347 Inc(Start);
348 s := s + IntToStr(y);
349 end;
350 Result := s;
351 end;
352 ASN1_NULL:
353 begin
354 Result := '';
355 Start := Start + ASNSize;
356 end;
357 else // unknown
358 begin
359 for n := 1 to ASNSize do
360 begin
361 c := AnsiChar(Buffer[Start]);
362 Inc(Start);
363 s := s + c;
364 end;
365 Result := s;
366 end;
367 end;
368end;
369
370{==============================================================================}
371function MibToId(Mib: String): AnsiString;
372var
373 x: Integer;
374
375 function WalkInt(var s: String): Integer;
376 var
377 x: Integer;
378 t: AnsiString;
379 begin
380 x := Pos('.', s);
381 if x < 1 then
382 begin
383 t := s;
384 s := '';
385 end
386 else
387 begin
388 t := Copy(s, 1, x - 1);
389 s := Copy(s, x + 1, Length(s) - x);
390 end;
391 Result := StrToIntDef(t, 0);
392 end;
393
394begin
395 Result := '';
396 x := WalkInt(Mib);
397 x := x * 40 + WalkInt(Mib);
398 Result := ASNEncOIDItem(x);
399 while Mib <> '' do
400 begin
401 x := WalkInt(Mib);
402 Result := Result + ASNEncOIDItem(x);
403 end;
404end;
405
406{==============================================================================}
407function IdToMib(const Id: AnsiString): String;
408var
409 x, y, n: Integer;
410begin
411 Result := '';
412 n := 1;
413 while Length(Id) + 1 > n do
414 begin
415 x := ASNDecOIDItem(n, Id);
416 if (n - 1) = 1 then
417 begin
418 y := x div 40;
419 x := x mod 40;
420 Result := IntToStr(y);
421 end;
422 Result := Result + '.' + IntToStr(x);
423 end;
424end;
425
426{==============================================================================}
427function IntMibToStr(const Value: AnsiString): AnsiString;
428var
429 n, y: Integer;
430begin
431 y := 0;
432 for n := 1 to Length(Value) - 1 do
433 y := y * 256 + Ord(Value[n]);
434 Result := IntToStr(y);
435end;
436
437{==============================================================================}
438function ASNdump(const Value: AnsiString): AnsiString;
439var
440 i, at, x, n: integer;
441 s, indent: AnsiString;
442 il: TStringList;
443begin
444 il := TStringList.Create;
445 try
446 Result := '';
447 i := 1;
448 indent := '';
449 while i < Length(Value) do
450 begin
451 for n := il.Count - 1 downto 0 do
452 begin
453 x := StrToIntDef(il[n], 0);
454 if x <= i then
455 begin
456 il.Delete(n);
457 Delete(indent, 1, 2);
458 end;
459 end;
460 s := ASNItem(i, Value, at);
461 Result := Result + indent + '$' + IntToHex(at, 2);
462 if (at and $20) > 0 then
463 begin
464 x := Length(s);
465 Result := Result + ' constructed: length ' + IntToStr(x);
466 indent := indent + ' ';
467 il.Add(IntToStr(x + i - 1));
468 end
469 else
470 begin
471 case at of
472 ASN1_BOOL:
473 Result := Result + ' BOOL: ';
474 ASN1_INT:
475 Result := Result + ' INT: ';
476 ASN1_ENUM:
477 Result := Result + ' ENUM: ';
478 ASN1_COUNTER:
479 Result := Result + ' COUNTER: ';
480 ASN1_GAUGE:
481 Result := Result + ' GAUGE: ';
482 ASN1_TIMETICKS:
483 Result := Result + ' TIMETICKS: ';
484 ASN1_OCTSTR:
485 Result := Result + ' OCTSTR: ';
486 ASN1_OPAQUE:
487 Result := Result + ' OPAQUE: ';
488 ASN1_OBJID:
489 Result := Result + ' OBJID: ';
490 ASN1_IPADDR:
491 Result := Result + ' IPADDR: ';
492 ASN1_NULL:
493 Result := Result + ' NULL: ';
494 else // other
495 Result := Result + ' unknown: ';
496 end;
497 if IsBinaryString(s) then
498 s := DumpExStr(s);
499 Result := Result + s;
500 end;
501 Result := Result + #$0d + #$0a;
502 end;
503 finally
504 il.Free;
505 end;
506end;
507
508{==============================================================================}
509
510end.
Note: See TracBrowser for help on using the repository browser.