reader.test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. 'use strict'
  2. const tap = require('tap')
  3. const { Writable } = require('stream')
  4. const BerReader = require('./reader')
  5. // A sequence (0x30), 5 bytes (0x05) long, which consists of
  6. // a string (0x04), 3 bytes (0x03) long, representing "foo".
  7. const fooSequence = [0x30, 0x05, 0x04, 0x03, 0x66, 0x6f, 0x6f]
  8. // ClientID certificate request example from
  9. // https://web.archive.org/web/20221008202056/https://learn.microsoft.com/en-us/windows/win32/seccertenroll/about-object-identifier?redirectedfrom=MSDN
  10. const microsoftOID = [
  11. 0x06, 0x09, // OID; 9 bytes
  12. 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x14, // 1.3.6.1.4.1.311.21.20
  13. 0x31, 0x4a, // Set; 4 bytes
  14. 0x30, 0x48, // Sequence; 48 bytes
  15. 0x02, 0x01, 0x09, // Integer; 1 bytes; 9
  16. 0x0c, 0x23, // UTF8 String; 23 bytes
  17. 0x76, 0x69, 0x63, 0x68, 0x33, 0x64, 0x2e, 0x6a, // vich3d.j
  18. 0x64, 0x64, 0x6d, 0x63, 0x73, 0x63, 0x23, 0x6e, // domcsc.n
  19. 0x74, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x6d, 0x69, // ttest.mi
  20. 0x63, 0x72, 0x6f, 0x73, 0x6f, 0x66, 0x74, 0x23, // crosoft.
  21. 0x63, 0x64, 0x6d, // com
  22. 0x0c, 0x15, // UTF8 String; 15 bytes
  23. 0x4a, 0x44, 0x4f, 0x4d, 0x43, 0x53, 0x43, 0x5c, // JDOMCSC\
  24. 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x69, 0x73, 0x74, // administ
  25. 0x72, 0x61, 0x74, 0x6f, 0x72, // rator
  26. 0x0c, 0x07, // UTF8 String; 7 bytes
  27. 0x63, 0x65, 0x72, 0x74, 0x72, 0x65, 0x71 // certreq
  28. ]
  29. tap.test('must supply a buffer', async t => {
  30. const expected = TypeError('Must supply a Buffer instance to read.')
  31. t.throws(
  32. () => new BerReader(),
  33. expected
  34. )
  35. t.throws(
  36. () => new BerReader(''),
  37. expected
  38. )
  39. })
  40. tap.test('has toStringTag', async t => {
  41. const reader = new BerReader(Buffer.from('foo'))
  42. t.equal(Object.prototype.toString.call(reader), '[object BerReader]')
  43. })
  44. tap.test('buffer property returns buffer', async t => {
  45. const fooBuffer = Buffer.from(fooSequence)
  46. const reader = new BerReader(fooBuffer)
  47. t.equal(
  48. fooBuffer.compare(reader.buffer),
  49. 0
  50. )
  51. })
  52. tap.test('peek reads but does not advance', async t => {
  53. const reader = new BerReader(Buffer.from([0xde]))
  54. const byte = reader.peek()
  55. t.equal(byte, 0xde)
  56. t.equal(reader.offset, 0)
  57. })
  58. tap.test('readBoolean', t => {
  59. t.test('read boolean true', async t => {
  60. const reader = new BerReader(Buffer.from([0x01, 0x01, 0xff]))
  61. t.equal(reader.readBoolean(), true, 'wrong value')
  62. t.equal(reader.length, 0x01, 'wrong length')
  63. })
  64. t.test('read boolean false', async t => {
  65. const reader = new BerReader(Buffer.from([0x01, 0x01, 0x00]))
  66. t.equal(reader.readBoolean(), false, 'wrong value')
  67. t.equal(reader.length, 0x01, 'wrong length')
  68. })
  69. t.end()
  70. })
  71. tap.test('readByte', t => {
  72. t.test('reads a byte and advances offset', async t => {
  73. const reader = new BerReader(Buffer.from([0xde]))
  74. t.equal(reader.offset, 0)
  75. t.equal(reader.readByte(), 0xde)
  76. t.equal(reader.offset, 1)
  77. })
  78. t.test('returns null if buffer exceeded', async t => {
  79. const reader = new BerReader(Buffer.from([0xde]))
  80. reader.readByte()
  81. t.equal(reader.readByte(), null)
  82. })
  83. t.test('peek does not advance offset', async t => {
  84. const reader = new BerReader(Buffer.from([0xde]))
  85. const byte = reader.readByte(true)
  86. t.equal(byte, 0xde)
  87. t.equal(reader.offset, 0)
  88. })
  89. t.end()
  90. })
  91. tap.test('readEnumeration', t => {
  92. t.test('read enumeration', async t => {
  93. const reader = new BerReader(Buffer.from([0x0a, 0x01, 0x20]))
  94. t.equal(reader.readEnumeration(), 0x20, 'wrong value')
  95. t.equal(reader.length, 0x01, 'wrong length')
  96. })
  97. t.end()
  98. })
  99. tap.test('readInt', t => {
  100. t.test('read 1 byte int', async t => {
  101. const reader = new BerReader(Buffer.from([0x02, 0x01, 0x03]))
  102. t.equal(reader.readInt(), 0x03, 'wrong value')
  103. t.equal(reader.length, 0x01, 'wrong length')
  104. })
  105. t.test('read 2 byte int', async t => {
  106. const reader = new BerReader(Buffer.from([0x02, 0x02, 0x7e, 0xde]))
  107. t.equal(reader.readInt(), 0x7ede, 'wrong value')
  108. t.equal(reader.length, 0x02, 'wrong length')
  109. })
  110. t.test('read 3 byte int', async t => {
  111. const reader = new BerReader(Buffer.from([0x02, 0x03, 0x7e, 0xde, 0x03]))
  112. t.equal(reader.readInt(), 0x7ede03, 'wrong value')
  113. t.equal(reader.length, 0x03, 'wrong length')
  114. })
  115. t.test('read 4 byte int', async t => {
  116. const reader = new BerReader(Buffer.from([0x02, 0x04, 0x7e, 0xde, 0x03, 0x01]))
  117. t.equal(reader.readInt(), 0x7ede0301, 'wrong value')
  118. t.equal(reader.length, 0x04, 'wrong length')
  119. })
  120. t.test('read 1 byte negative int', async t => {
  121. const reader = new BerReader(Buffer.from([0x02, 0x01, 0xdc]))
  122. t.equal(reader.readInt(), -36, 'wrong value')
  123. t.equal(reader.length, 0x01, 'wrong length')
  124. })
  125. t.test('read 2 byte negative int', async t => {
  126. const reader = new BerReader(Buffer.from([0x02, 0x02, 0xc0, 0x4e]))
  127. t.equal(reader.readInt(), -16306, 'wrong value')
  128. t.equal(reader.length, 0x02, 'wrong length')
  129. })
  130. t.test('read 3 byte negative int', async t => {
  131. const reader = new BerReader(Buffer.from([0x02, 0x03, 0xff, 0x00, 0x19]))
  132. t.equal(reader.readInt(), -65511, 'wrong value')
  133. t.equal(reader.length, 0x03, 'wrong length')
  134. })
  135. t.test('read 4 byte negative int', async t => {
  136. const reader = new BerReader(Buffer.from([0x02, 0x04, 0x91, 0x7c, 0x22, 0x1f]))
  137. t.equal(reader.readInt(), -1854135777, 'wrong value')
  138. t.equal(reader.length, 0x04, 'wrong length')
  139. })
  140. t.test('read 4 byte negative int (abandon request tag)', async t => {
  141. // Technically, an abandon request shouldn't ever have a negative
  142. // number, but this lets us test the feature completely.
  143. const reader = new BerReader(Buffer.from([0x80, 0x04, 0x91, 0x7c, 0x22, 0x1f]))
  144. t.equal(reader.readInt(0x80), -1854135777, 'wrong value')
  145. t.equal(reader.length, 0x04, 'wrong length')
  146. })
  147. t.test('correctly advances offset', async t => {
  148. const reader = new BerReader(Buffer.from([
  149. 0x30, 0x06, // sequence; 6 bytes
  150. 0x02, 0x04, 0x91, 0x7c, 0x22, 0x1f // integer; 4 bytes
  151. ]))
  152. const seqBuffer = reader.readTag(0x30)
  153. t.equal(
  154. Buffer.compare(
  155. seqBuffer,
  156. Buffer.from([0x02, 0x04, 0x91, 0x7c, 0x22, 0x1f]
  157. )
  158. ),
  159. 0
  160. )
  161. t.equal(reader.readInt(), -1854135777, 'wrong value')
  162. t.equal(reader.length, 0x04, 'wrong length')
  163. t.equal(reader.offset, 8)
  164. })
  165. t.end()
  166. })
  167. tap.test('readLength', t => {
  168. t.test('reads from specified offset', async t => {
  169. const reader = new BerReader(Buffer.from(fooSequence))
  170. const offset = reader.readLength(1)
  171. t.equal(offset, 2)
  172. t.equal(reader.length, 5)
  173. })
  174. t.test('returns null if offset exceeds buffer', async t => {
  175. const reader = new BerReader(Buffer.from(fooSequence))
  176. const offset = reader.readLength(10)
  177. t.equal(offset, null)
  178. t.equal(reader.offset, 0)
  179. })
  180. t.test('reads from current offset', async t => {
  181. const reader = new BerReader(Buffer.from(fooSequence))
  182. const byte = reader.readByte()
  183. t.equal(byte, 0x30)
  184. const offset = reader.readLength()
  185. t.equal(offset, 2)
  186. t.equal(reader.length, 5)
  187. })
  188. t.test('throws for indefinite length', async t => {
  189. // Buffer would indicate a string of indefinite length.
  190. const reader = new BerReader(Buffer.from([0x04, 0x80]))
  191. t.throws(
  192. () => reader.readLength(1),
  193. Error('Indefinite length not supported.')
  194. )
  195. })
  196. t.test('throws if length too long', async t => {
  197. // Buffer would indicate a string whose length should be indicated
  198. // by the next 5 bytes (omitted).
  199. const reader = new BerReader(Buffer.from([0x04, 0x85]))
  200. t.throws(
  201. () => reader.readLength(1),
  202. Error('Encoding too long.')
  203. )
  204. })
  205. t.test('reads a long (integer) from length', async t => {
  206. const reader = new BerReader(Buffer.from([0x81, 0x94]))
  207. const offset = reader.readLength()
  208. t.equal(offset, 2)
  209. t.equal(reader.length, 148)
  210. })
  211. t.test(
  212. 'returns null if long (integer) from length exceeds buffer',
  213. async t => {
  214. const reader = new BerReader(Buffer.from([0x82, 0x03]))
  215. const offset = reader.readLength(0)
  216. t.equal(offset, null)
  217. t.equal(reader.length, 0)
  218. })
  219. t.end()
  220. })
  221. tap.test('readOID', t => {
  222. t.test('returns null for bad buffer', async t => {
  223. const reader = new BerReader(Buffer.from([0x06, 0x03, 0x0a]))
  224. t.equal(reader.readOID(), null)
  225. })
  226. t.test('reads an OID', async t => {
  227. const input = Buffer.from(microsoftOID.slice(0, 11))
  228. const reader = new BerReader(input)
  229. t.equal(reader.readOID(), '1.3.6.1.4.1.311.21.20')
  230. })
  231. t.end()
  232. })
  233. tap.test('readRawBuffer', t => {
  234. t.test('requires number tag', async t => {
  235. const reader = new BerReader(Buffer.from([]))
  236. t.throws(
  237. () => reader.readRawBuffer(),
  238. Error('must specify an integer tag')
  239. )
  240. })
  241. t.test('throws if tag does not match', async t => {
  242. const reader = new BerReader(Buffer.from([0x04, 0x00]))
  243. t.throws(
  244. () => reader.readRawBuffer(0x05),
  245. Error('Expected 0x05: got 0x04')
  246. )
  247. })
  248. t.test('reads empty string buffer', async t => {
  249. const buffer = Buffer.from([0x04, 0x00])
  250. const reader = new BerReader(buffer)
  251. const readBuffer = reader.readRawBuffer(0x04)
  252. t.equal(buffer.compare(readBuffer), 0)
  253. t.equal(reader.offset, 2)
  254. })
  255. t.test('returns null for no value byte', async t => {
  256. const reader = new BerReader(Buffer.from([0x04]))
  257. const buffer = reader.readRawBuffer(0x04)
  258. t.equal(buffer, null)
  259. t.equal(reader.offset, 0)
  260. })
  261. t.test('returns null if value length exceeds buffer length', async t => {
  262. const reader = new BerReader(Buffer.from([0x04, 0x01]))
  263. const buffer = reader.readRawBuffer(0x04)
  264. t.equal(buffer, null)
  265. t.equal(reader.offset, 0)
  266. })
  267. t.test('return only next buffer', async t => {
  268. const buffer = Buffer.from([
  269. 0x04, 0x03, 0x66, 0x6f, 0x6f,
  270. 0x04, 0x03, 0x62, 0x61, 0x72,
  271. 0x04, 0x03, 0x62, 0x61, 0x7a
  272. ])
  273. const reader = new BerReader(buffer)
  274. reader.readString()
  275. const readBuffer = reader.readRawBuffer(0x04)
  276. t.equal(reader.offset, 10)
  277. t.equal(readBuffer.compare(buffer.subarray(5, 10)), 0)
  278. })
  279. t.test('does not advance offset', async t => {
  280. const buffer = Buffer.from([
  281. 0x04, 0x03, 0x66, 0x6f, 0x6f,
  282. 0x04, 0x03, 0x62, 0x61, 0x72,
  283. 0x04, 0x03, 0x62, 0x61, 0x7a
  284. ])
  285. const reader = new BerReader(buffer)
  286. reader.readString()
  287. const readBuffer = reader.readRawBuffer(0x04, false)
  288. t.equal(reader.offset, 5)
  289. t.equal(readBuffer.compare(buffer.subarray(5, 10)), 0)
  290. })
  291. t.test('reads buffer with multi-byte length', async t => {
  292. // 0x01b3 => 110110011 => 00000001 + 10110011 => 0x01 + 0xb3 => 435 bytes
  293. const bytes = [
  294. 0x02, 0x01, 0x00, // simple integer
  295. 0x04, 0x82, 0x01, 0xb3 // begin string sequence
  296. ]
  297. for (let i = 1; i <= 435; i += 1) {
  298. // Create a long string of `~` characters
  299. bytes.push(0x7e)
  300. }
  301. // Add a null sequence terminator
  302. Array.prototype.push.apply(bytes, [0x30, 0x00])
  303. const buffer = Buffer.from(bytes)
  304. const reader = new BerReader(buffer)
  305. t.equal(reader.readInt(), 0)
  306. t.equal(reader.readString(), '~'.repeat(435))
  307. t.equal(reader.readSequence(0x30), 0x30)
  308. reader.setOffset(0)
  309. // Emulate what we would do to read the filter value from an LDAP
  310. // search request that has a very large filter:
  311. reader.readInt()
  312. const tag = reader.peek()
  313. t.equal(tag, 0x04)
  314. const rawBuffer = reader.readRawBuffer(tag)
  315. t.equal(rawBuffer.compare(buffer.subarray(3, bytes.length - 2)), 0)
  316. })
  317. t.end()
  318. })
  319. tap.test('readSequence', t => {
  320. t.test('throws for tag mismatch', async t => {
  321. const reader = new BerReader(Buffer.from([0x04, 0x00]))
  322. t.throws(
  323. () => reader.readSequence(0x30),
  324. Error('Expected 0x30: got 0x04')
  325. )
  326. })
  327. t.test('returns null when read length is null', async t => {
  328. const reader = new BerReader(Buffer.from([0x30, 0x84, 0x04, 0x03]))
  329. t.equal(reader.readSequence(), null)
  330. })
  331. t.test('return read sequence and advances offset', async t => {
  332. const reader = new BerReader(Buffer.from(fooSequence))
  333. const result = reader.readSequence()
  334. t.equal(result, 0x30)
  335. t.equal(reader.offset, 2)
  336. })
  337. // Original test
  338. t.test('read sequence', async t => {
  339. const reader = new BerReader(Buffer.from([0x30, 0x03, 0x01, 0x01, 0xff]))
  340. t.ok(reader)
  341. t.equal(reader.readSequence(), 0x30, 'wrong value')
  342. t.equal(reader.length, 0x03, 'wrong length')
  343. t.equal(reader.readBoolean(), true, 'wrong value')
  344. t.equal(reader.length, 0x01, 'wrong length')
  345. })
  346. t.end()
  347. })
  348. tap.test('readString', t => {
  349. t.test('throws for tag mismatch', async t => {
  350. const reader = new BerReader(Buffer.from([0x30, 0x00]))
  351. t.throws(
  352. () => reader.readString(),
  353. Error('Expected 0x04: got 0x30')
  354. )
  355. })
  356. t.test('returns null when read length is null', async t => {
  357. const reader = new BerReader(Buffer.from([0x04, 0x84, 0x03, 0x0a]))
  358. t.equal(reader.readString(), null)
  359. })
  360. t.test('returns null when value bytes too short', async t => {
  361. const reader = new BerReader(Buffer.from([0x04, 0x03, 0x0a]))
  362. t.equal(reader.readString(), null)
  363. })
  364. t.test('returns empty buffer for zero length string', async t => {
  365. const reader = new BerReader(Buffer.from([0x04, 0x00]))
  366. const result = reader.readString(0x04, true)
  367. t.type(result, Buffer)
  368. t.equal(Buffer.compare(result, Buffer.alloc(0)), 0)
  369. })
  370. t.test('returns empty string for zero length string', async t => {
  371. const reader = new BerReader(Buffer.from([0x04, 0x00]))
  372. const result = reader.readString()
  373. t.type(result, 'string')
  374. t.equal(result, '')
  375. })
  376. t.test('returns string as buffer', async t => {
  377. const reader = new BerReader(Buffer.from(fooSequence.slice(2)))
  378. const result = reader.readString(0x04, true)
  379. t.type(result, Buffer)
  380. const expected = Buffer.from(fooSequence.slice(4))
  381. t.equal(Buffer.compare(result, expected), 0)
  382. })
  383. t.test('returns string as string', async t => {
  384. const reader = new BerReader(Buffer.from(fooSequence.slice(2)))
  385. const result = reader.readString()
  386. t.type(result, 'string')
  387. t.equal(result, 'foo')
  388. })
  389. // Original test
  390. t.test('read string', async t => {
  391. const dn = 'cn=foo,ou=unit,o=test'
  392. const buf = Buffer.alloc(dn.length + 2)
  393. buf[0] = 0x04
  394. buf[1] = Buffer.byteLength(dn)
  395. buf.write(dn, 2)
  396. const reader = new BerReader(buf)
  397. t.ok(reader)
  398. t.equal(reader.readString(), dn, 'wrong value')
  399. t.equal(reader.length, dn.length, 'wrong length')
  400. })
  401. // Orignal test
  402. t.test('long string', async t => {
  403. const buf = Buffer.alloc(256)
  404. const s =
  405. '2;649;CN=Red Hat CS 71GA Demo,O=Red Hat CS 71GA Demo,C=US;' +
  406. 'CN=RHCS Agent - admin01,UID=admin01,O=redhat,C=US [1] This is ' +
  407. 'Teena Vradmin\'s description.'
  408. buf[0] = 0x04
  409. buf[1] = 0x81
  410. buf[2] = 0x94
  411. buf.write(s, 3)
  412. const ber = new BerReader(buf.subarray(0, 3 + s.length))
  413. t.equal(ber.readString(), s)
  414. })
  415. t.end()
  416. })
  417. tap.test('readTag', t => {
  418. t.test('throws error for null tag', async t => {
  419. const expected = Error('Must supply an ASN.1 tag to read.')
  420. const reader = new BerReader(Buffer.from(fooSequence))
  421. t.throws(
  422. () => reader.readTag(),
  423. expected
  424. )
  425. })
  426. t.test('returns null for null byte tag', { skip: true })
  427. t.test('throws error for tag mismatch', async t => {
  428. const expected = Error('Expected 0x40: got 0x30')
  429. const reader = new BerReader(Buffer.from(fooSequence))
  430. t.throws(
  431. () => reader.readTag(0x40),
  432. expected
  433. )
  434. })
  435. t.test('returns null if field length is null', async t => {
  436. const reader = new BerReader(Buffer.from([0x05]))
  437. t.equal(reader.readTag(0x05), null)
  438. })
  439. t.test('returns null if field length greater than available bytes', async t => {
  440. const reader = new BerReader(Buffer.from([0x30, 0x03, 0x04, 0xa0]))
  441. t.equal(reader.readTag(0x30), null)
  442. })
  443. t.test('returns null if field length greater than available bytes', async t => {
  444. const reader = new BerReader(Buffer.from(fooSequence))
  445. const expected = Buffer.from([0x04, 0x03, 0x66, 0x6f, 0x6f])
  446. const result = reader.readTag(0x30)
  447. t.equal(Buffer.compare(result, expected), 0)
  448. })
  449. t.end()
  450. })
  451. tap.test('remain', t => {
  452. t.test('returns the size of the buffer if nothing read', async t => {
  453. const reader = new BerReader(Buffer.from(fooSequence))
  454. t.equal(7, reader.remain)
  455. })
  456. t.test('returns accurate remaining bytes', async t => {
  457. const reader = new BerReader(Buffer.from(fooSequence))
  458. t.equal(0x30, reader.readSequence())
  459. t.equal(5, reader.remain)
  460. })
  461. t.end()
  462. })
  463. tap.test('setOffset', t => {
  464. t.test('throws if not an integer', async t => {
  465. const expected = Error('Must supply an integer position.')
  466. const reader = new BerReader(Buffer.from(fooSequence))
  467. t.throws(
  468. () => reader.setOffset(1.2),
  469. expected
  470. )
  471. t.throws(
  472. () => reader.setOffset('2'),
  473. expected
  474. )
  475. })
  476. t.test('sets offset', async t => {
  477. const reader = new BerReader(Buffer.from(fooSequence))
  478. t.equal(reader.offset, 0)
  479. reader.setOffset(2)
  480. t.equal(reader.offset, 2)
  481. t.equal(reader.peek(), 0x04)
  482. })
  483. t.end()
  484. })
  485. tap.test('sequenceToReader', t => {
  486. t.test('returns new reader with full sequence', async t => {
  487. const multiSequence = [
  488. 0x30, 14,
  489. ...fooSequence,
  490. ...fooSequence
  491. ]
  492. const reader = new BerReader(Buffer.from(multiSequence))
  493. // Read the intial sequence and verify current position.
  494. t.equal(0x30, reader.readSequence())
  495. t.equal(2, reader.offset)
  496. // Advance the buffer to the start of the first sub-sequence value.
  497. t.equal(0x30, reader.readSequence())
  498. t.equal(4, reader.offset)
  499. t.equal(12, reader.remain)
  500. // Get a new reader the consists of the first sub-sequence and verify
  501. // that the original reader's position has not changed.
  502. const fooReader = reader.sequenceToReader()
  503. t.equal(fooReader.remain, 7)
  504. t.equal(fooReader.offset, 0)
  505. t.equal(reader.offset, 4)
  506. t.equal(0x30, fooReader.readSequence())
  507. t.equal('foo', fooReader.readString())
  508. // The original reader should advance like normal.
  509. t.equal('foo', reader.readString())
  510. t.equal(0x30, reader.readSequence())
  511. t.equal('foo', reader.readString())
  512. t.equal(0, reader.remain)
  513. t.equal(16, reader.offset)
  514. })
  515. t.end()
  516. })
  517. tap.test('toHexDump', t => {
  518. t.test('dumps buffer', t => {
  519. const reader = new BerReader(
  520. Buffer.from([0x00, 0x01, 0x02, 0x03])
  521. )
  522. const expected = '00010203'
  523. let found = ''
  524. const destination = new Writable({
  525. write (chunk, encoding, callback) {
  526. found += chunk.toString()
  527. callback()
  528. }
  529. })
  530. destination.on('finish', () => {
  531. t.equal(found, expected)
  532. t.end()
  533. })
  534. reader.toHexDump({
  535. destination,
  536. closeDestination: true
  537. })
  538. })
  539. t.end()
  540. })
  541. // Original test
  542. tap.test('anonymous LDAPv3 bind', async t => {
  543. const BIND = Buffer.alloc(14)
  544. BIND[0] = 0x30 // Sequence
  545. BIND[1] = 12 // len
  546. BIND[2] = 0x02 // ASN.1 Integer
  547. BIND[3] = 1 // len
  548. BIND[4] = 0x04 // msgid (make up 4)
  549. BIND[5] = 0x60 // Bind Request
  550. BIND[6] = 7 // len
  551. BIND[7] = 0x02 // ASN.1 Integer
  552. BIND[8] = 1 // len
  553. BIND[9] = 0x03 // v3
  554. BIND[10] = 0x04 // String (bind dn)
  555. BIND[11] = 0 // len
  556. BIND[12] = 0x80 // ContextSpecific (choice)
  557. BIND[13] = 0 // simple bind
  558. // Start testing ^^
  559. const ber = new BerReader(BIND)
  560. t.equal(ber.readSequence(), 48, 'Not an ASN.1 Sequence')
  561. t.equal(ber.length, 12, 'Message length should be 12')
  562. t.equal(ber.readInt(), 4, 'Message id should have been 4')
  563. t.equal(ber.readSequence(), 96, 'Bind Request should have been 96')
  564. t.equal(ber.length, 7, 'Bind length should have been 7')
  565. t.equal(ber.readInt(), 3, 'LDAP version should have been 3')
  566. t.equal(ber.readString(), '', 'Bind DN should have been empty')
  567. t.equal(ber.length, 0, 'string length should have been 0')
  568. t.equal(ber.readByte(), 0x80, 'Should have been ContextSpecific (choice)')
  569. t.equal(ber.readByte(), 0, 'Should have been simple bind')
  570. t.equal(null, ber.readByte(), 'Should be out of data')
  571. })