IdASN1Util.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.2 3/3/2005 9:13:36 AM JPMugaas
  18. Should work in DotNET.
  19. Rev 1.1 02/03/2005 00:09:14 CCostelloe
  20. Bug fix (high bit treated as sign instead of MSB)
  21. Rev 1.0 11/14/2002 02:12:30 PM JPMugaas
  22. }
  23. unit IdASN1Util;
  24. // REVIEW: Licensing problem
  25. // 1) Is this only used by SNMP? If so it should be merged there.
  26. // 2) MPL conflicts with Indy's BSD. We need permission to distribute under BSD as well.
  27. // 3) A comment needs to be added that Indy has permission to use this
  28. {
  29. |==============================================================================|
  30. | Project : Delphree - Synapse | 001.003.004 |
  31. |==============================================================================|
  32. | Content: support for ASN.1 coding and decoding |
  33. |==============================================================================|
  34. | The contents of this file are subject to the Mozilla Public License Ver. 1.1 |
  35. | (the "License"); you may not use this file except in compliance with the |
  36. | License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ |
  37. | |
  38. | Software distributed under the License is distributed on an "AS IS" basis, |
  39. | WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for |
  40. | the specific language governing rights and limitations under the License. |
  41. |==============================================================================|
  42. | The Original Code is Synapse Delphi Library. |
  43. |==============================================================================|
  44. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  45. | Portions created by Lukas Gebauer are Copyright (c) 1999,2000,2001. |
  46. | Portions created by Hernan Sanchez are Copyright (c) 2000. |
  47. | All Rights Reserved. |
  48. |==============================================================================|
  49. | Contributor(s): |
  50. | Hernan Sanchez ([email protected]) |
  51. |==============================================================================|
  52. | History: see HISTORY.HTM from distribution package |
  53. | (Found at URL: http://www.ararat.cz/synapse/) |
  54. |==============================================================================|
  55. }
  56. {$i IdOverflowCheckingOff.inc}
  57. {$WEAKPACKAGEUNIT ON}
  58. interface
  59. {$i IdCompilerDefines.inc}
  60. uses
  61. {$IFNDEF HAS_UInt32}
  62. IdGlobal,
  63. {$ENDIF}
  64. SysUtils;
  65. const
  66. ASN1_INT = $02;
  67. ASN1_OCTSTR = $04;
  68. ASN1_NULL = $05;
  69. ASN1_OBJID = $06;
  70. ASN1_SEQ = $30;
  71. ASN1_IPADDR = $40;
  72. ASN1_COUNTER = $41;
  73. ASN1_GAUGE = $42;
  74. ASN1_TIMETICKS = $43;
  75. ASN1_OPAQUE = $44;
  76. ASN1_APP_COUNTER64 = $46;
  77. // TODO: float, double, int64, uint64
  78. function ASNEncOIDItem(Value: UInt32): string;
  79. function ASNDecOIDItem(var Start: Integer; const Buffer: string): UInt32;
  80. function ASNEncLen(Len: Integer): string;
  81. function ASNDecLen(var Start: Integer; const Buffer: string): Integer;
  82. function ASNEncInt(Value: Integer): string;
  83. function ASNEncUInt(Value: Integer): string;
  84. function ASNObject(const Data: string; ASNType: Integer): string;
  85. function ASNItem(var Start: Integer; const Buffer: string;
  86. var ValueType: Integer): string;
  87. function MibToId(Mib: string): string;
  88. function IdToMib(const Id: string): string;
  89. function IntMibToStr(const Value: string): string;
  90. implementation
  91. {$IFDEF HAS_UInt32}
  92. uses
  93. IdGlobal;
  94. {$ENDIF}
  95. {==============================================================================}
  96. function ASNEncOIDItem(Value: UInt32): string;
  97. var
  98. x, xm: UInt32;
  99. b: Boolean;
  100. begin
  101. x := Value;
  102. b := False;
  103. Result := ''; {Do not Localize}
  104. repeat
  105. xm := x mod 128;
  106. x := x div 128;
  107. if b then
  108. xm := xm or $80;
  109. if x > 0 then
  110. b := True;
  111. Result := Char(xm) + Result;
  112. until x = 0;
  113. end;
  114. {==============================================================================}
  115. function ASNDecOIDItem(var Start: Integer; const Buffer: string): UInt32;
  116. var
  117. x: UInt32;
  118. b: Boolean;
  119. begin
  120. Result := 0;
  121. repeat
  122. Result := Result * 128;
  123. x := Ord(Buffer[Start]);
  124. Inc(Start);
  125. b := x > $7F;
  126. x := x and $7F;
  127. Result := Result + x;
  128. until not b;
  129. end;
  130. {==============================================================================}
  131. function ASNEncLen(Len: Integer): string;
  132. var
  133. x, y: Integer;
  134. begin
  135. if Len < $80 then
  136. Result := Char(Len)
  137. else
  138. begin
  139. x := Len;
  140. Result := ''; {Do not Localize}
  141. repeat
  142. y := x mod 256;
  143. x := x div 256;
  144. Result := Char(y) + Result;
  145. until x = 0;
  146. y := Length(Result);
  147. y := y or $80;
  148. Result := Char(y) + Result;
  149. end;
  150. end;
  151. {==============================================================================}
  152. function ASNDecLen(var Start: Integer; const Buffer: string): Integer;
  153. var
  154. x, n: Integer;
  155. begin
  156. x := Ord(Buffer[Start]);
  157. Inc(Start);
  158. if x < $80 then
  159. Result := x
  160. else
  161. begin
  162. Result := 0;
  163. x := x and $7F;
  164. for n := 1 to x do
  165. begin
  166. Result := Result * 256;
  167. x := Ord(Buffer[Start]);
  168. Inc(Start);
  169. Result := Result + x;
  170. end;
  171. end;
  172. end;
  173. {==============================================================================}
  174. function ASNEncInt(Value: Integer): string;
  175. var
  176. x, y: UInt32;
  177. neg: Boolean;
  178. {$IFDEF STRING_IS_IMMUTABLE}
  179. LSB: TIdStringBuilder;
  180. {$ENDIF}
  181. begin
  182. neg := Value < 0;
  183. x := Abs(Value);
  184. if neg then begin
  185. x := not (x - 1);
  186. end;
  187. Result := ''; {Do not Localize}
  188. {$IFDEF STRING_IS_IMMUTABLE}
  189. LSB := TIdStringBuilder.Create;
  190. {$ENDIF}
  191. repeat
  192. y := x mod 256;
  193. x := x div 256;
  194. {$IFDEF STRING_IS_IMMUTABLE}
  195. LSB.Insert(0, Char(y));
  196. {$ELSE}
  197. Result := Char(y) + Result;
  198. {$ENDIF}
  199. until x = 0;
  200. if (not neg) then
  201. begin
  202. {$IFDEF STRING_IS_IMMUTABLE}
  203. if (LSB[0] > #$7F) then begin
  204. LSB.Insert(0, #0);
  205. end;
  206. {$ELSE}
  207. if (Result[1] > #$7F) then begin
  208. Result := #0 + Result;
  209. end;
  210. {$ENDIF}
  211. end;
  212. {$IFDEF STRING_IS_IMMUTABLE}
  213. Result := LSB.ToString;
  214. {$ENDIF}
  215. end;
  216. {==============================================================================}
  217. function ASNEncUInt(Value: Integer): string;
  218. var
  219. x, y: Integer;
  220. neg: Boolean;
  221. {$IFDEF STRING_IS_IMMUTABLE}
  222. LSB: TIdStringBuilder;
  223. {$ENDIF}
  224. begin
  225. neg := Value < 0;
  226. x := Value;
  227. if neg then begin
  228. x := x and $7FFFFFFF;
  229. end;
  230. Result := ''; {Do not Localize}
  231. {$IFDEF STRING_IS_IMMUTABLE}
  232. LSB := TIdStringBuilder.Create;
  233. {$ENDIF}
  234. repeat
  235. y := x mod 256;
  236. x := x div 256;
  237. {$IFDEF STRING_IS_IMMUTABLE}
  238. LSB.Insert(0, Char(y));
  239. {$ELSE}
  240. Result := Char(y) + Result;
  241. {$ENDIF}
  242. until x = 0;
  243. if neg then begin
  244. {$IFDEF STRING_IS_IMMUTABLE}
  245. LSB[0] := Char(Ord(LSB[0]) or $80);
  246. {$ELSE}
  247. Result[1] := Char(Ord(Result[1]) or $80);
  248. {$ENDIF}
  249. end;
  250. {$IFDEF STRING_IS_IMMUTABLE}
  251. Result := LSB.ToString;
  252. {$ENDIF}
  253. end;
  254. {==============================================================================}
  255. function ASNObject(const Data: string; ASNType: Integer): string;
  256. begin
  257. Result := Char(ASNType) + ASNEncLen(Length(Data)) + Data;
  258. end;
  259. {==============================================================================}
  260. function ASNItem(var Start: Integer; const Buffer: string;
  261. var ValueType: Integer): string;
  262. var
  263. ASNType: Integer;
  264. ASNSize: Integer;
  265. y, n: Integer;
  266. x: byte;
  267. {$IFDEF STRING_IS_IMMUTABLE}
  268. LSB: TIdStringBuilder;
  269. {$ELSE}
  270. s: string;
  271. {$ENDIF}
  272. neg: Boolean;
  273. l: Integer;
  274. z: Int64;
  275. begin
  276. Result := ''; {Do not Localize}
  277. ValueType := ASN1_NULL;
  278. l := Length(Buffer);
  279. if l < (Start + 1) then begin
  280. Exit;
  281. end;
  282. ASNType := Ord(Buffer[Start]);
  283. ValueType := ASNType;
  284. Inc(Start);
  285. ASNSize := ASNDecLen(Start, Buffer);
  286. if (Start + ASNSize - 1) > l then begin
  287. Exit;
  288. end;
  289. if (ASNType and $20) > 0 then begin
  290. Result := '$' + IntToHex(ASNType, 2) {Do not Localize}
  291. end else
  292. begin
  293. case ASNType of
  294. ASN1_INT:
  295. begin
  296. y := 0;
  297. neg := False;
  298. for n := 1 to ASNSize do
  299. begin
  300. x := Ord(Buffer[Start]);
  301. if (n = 1) and (x > $7F) then begin
  302. neg := True;
  303. end;
  304. if neg then begin
  305. x := not x;
  306. end;
  307. y := y * 256 + x;
  308. Inc(Start);
  309. end;
  310. if neg then begin
  311. y := -(y + 1);
  312. end;
  313. Result := IntToStr(y);
  314. end;
  315. ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS, //Typically a 32-bit _unsigned_ number
  316. ASN1_APP_COUNTER64:
  317. // TODO: int64, uint64
  318. begin
  319. z := 0;
  320. for n := 1 to ASNSize do begin
  321. x := Ord(Buffer[Start]); //get the byte
  322. y := x; //promote to an integer
  323. z := (z * 256) + y; //now accumulate value
  324. Inc(Start);
  325. end;
  326. Result := IntToStr(z);
  327. end;
  328. // TODO: float, double
  329. ASN1_OCTSTR, ASN1_OPAQUE:
  330. begin
  331. {$IFDEF STRING_IS_IMMUTABLE}
  332. LSB := TIdStringBuilder.Create(ASNSize);
  333. {$ELSE}
  334. SetLength(s, ASNSize);
  335. {$ENDIF}
  336. for n := 1 to ASNSize do
  337. begin
  338. {$IFDEF STRING_IS_IMMUTABLE}
  339. LSB.Append(Char(Buffer[Start]));
  340. {$ELSE}
  341. s[n] := Char(Buffer[Start]);
  342. {$ENDIF}
  343. Inc(Start);
  344. end;
  345. {$IFDEF STRING_IS_IMMUTABLE}
  346. Result := LSB.ToString;
  347. {$ELSE}
  348. Result := s;
  349. {$ENDIF}
  350. end;
  351. ASN1_OBJID:
  352. begin
  353. {$IFDEF STRING_IS_IMMUTABLE}
  354. LSB := TIdStringBuilder.Create(ASNSize);
  355. {$ELSE}
  356. SetLength(s, ASNSize);
  357. {$ENDIF}
  358. for n := 1 to ASNSize do
  359. begin
  360. {$IFDEF STRING_IS_IMMUTABLE}
  361. LSB.Append(Char(Buffer[Start]));
  362. {$ELSE}
  363. s[n] := Char(Buffer[Start]);
  364. {$ENDIF}
  365. Inc(Start);
  366. end;
  367. Result := IdToMib(
  368. {$IFDEF STRING_IS_IMMUTABLE}
  369. LSB.ToString
  370. {$ELSE}
  371. s
  372. {$ENDIF}
  373. );
  374. end;
  375. ASN1_IPADDR:
  376. begin
  377. {$IFDEF STRING_IS_IMMUTABLE}
  378. LSB := TIdStringBuilder.Create(15);
  379. {$ELSE}
  380. s := ''; {Do not Localize}
  381. {$ENDIF}
  382. for n := 1 to ASNSize do
  383. begin
  384. if (n <> 1) then begin
  385. {$IFDEF STRING_IS_IMMUTABLE}
  386. LSB.Append('.'); {Do not Localize}
  387. {$ELSE}
  388. s := s + '.'; {Do not Localize}
  389. {$ENDIF}
  390. end;
  391. y := Ord(Buffer[Start]);
  392. Inc(Start);
  393. {$IFDEF STRING_IS_IMMUTABLE}
  394. LSB.Append(y);
  395. {$ELSE}
  396. s := s + IntToStr(y);
  397. {$ENDIF}
  398. end;
  399. {$IFDEF STRING_IS_IMMUTABLE}
  400. Result := LSB.ToString;
  401. {$ELSE}
  402. Result := s;
  403. {$ENDIF}
  404. end;
  405. ASN1_NULL:
  406. begin
  407. Result := '';
  408. Inc(Start, ASNSize);
  409. end;
  410. else // unknown
  411. begin
  412. {$IFDEF STRING_IS_IMMUTABLE}
  413. LSB := TIdStringBuilder.Create(ASNSize);
  414. {$ELSE}
  415. SetLength(s, ASNSize);
  416. {$ENDIF}
  417. for n := 1 to ASNSize do
  418. begin
  419. {$IFDEF STRING_IS_IMMUTABLE}
  420. LSB.Append(Char(Buffer[Start]));
  421. {$ELSE}
  422. s[n] := Char(Buffer[Start]);
  423. {$ENDIF}
  424. Inc(Start);
  425. end;
  426. {$IFDEF STRING_IS_IMMUTABLE}
  427. Result := LSB.ToString;
  428. {$ELSE}
  429. Result := s;
  430. {$ENDIF}
  431. end;
  432. end;
  433. end;
  434. end;
  435. {==============================================================================}
  436. function MibToId(Mib: string): string;
  437. var
  438. x: UInt32;
  439. function WalkInt(var s: string): UInt32;
  440. var
  441. lx: Integer;
  442. t: string;
  443. begin
  444. lx := Pos('.', s); {Do not Localize}
  445. if lx < 1 then
  446. begin
  447. t := s;
  448. s := ''; {Do not Localize}
  449. end
  450. else
  451. begin
  452. t := Copy(s, 1, lx - 1);
  453. s := Copy(s, lx + 1, MaxInt);
  454. end;
  455. // TODO: verify the returned value is in the range of UInt32!
  456. Result := IndyStrToInt64(t, 0);
  457. end;
  458. begin
  459. Result := ''; {Do not Localize}
  460. x := WalkInt(Mib);
  461. x := x * 40 + WalkInt(Mib);
  462. Result := ASNEncOIDItem(x);
  463. while Mib <> '' do {Do not Localize}
  464. begin
  465. x := WalkInt(Mib);
  466. Result := Result + ASNEncOIDItem(x);
  467. end;
  468. end;
  469. {==============================================================================}
  470. {$IFNDEF HAS_UIntToStr}
  471. function UIntToStr(AValue: UInt32): string;
  472. {$IFDEF USE_INLINE}inline;{$ENDIF}
  473. begin
  474. Result := SysUtils.IntToStr(Int64(AValue));
  475. end;
  476. {$ENDIF}
  477. function IdToMib(const Id: string): string;
  478. var
  479. x, y: UInt32;
  480. n: Integer;
  481. begin
  482. Result := ''; {Do not Localize}
  483. n := 1;
  484. while Length(Id) + 1 > n do
  485. begin
  486. x := ASNDecOIDItem(n, Id);
  487. if (n - 1) = 1 then
  488. begin
  489. y := x div 40;
  490. x := x mod 40;
  491. Result := UIntToStr(y);
  492. end;
  493. Result := Result + '.' + UIntToStr(x); {Do not Localize}
  494. end;
  495. end;
  496. {==============================================================================}
  497. function IntMibToStr(const Value: string): string;
  498. var
  499. n, y: Integer;
  500. begin
  501. y := 0;
  502. for n := 1 to Length(Value) - 1 do begin
  503. y := y * 256 + Ord(Value[n]);
  504. end;
  505. Result := IntToStr(y);
  506. end;
  507. {==============================================================================}
  508. end.