Buffer.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
  4. *
  5. * (c) ZeroTier, Inc.
  6. * https://www.zerotier.com/
  7. */
  8. #ifndef ZT_BUFFER_HPP
  9. #define ZT_BUFFER_HPP
  10. #include "Constants.hpp"
  11. #include "Utils.hpp"
  12. #include <algorithm>
  13. #include <stdint.h>
  14. #include <string.h>
  15. #if defined(__GNUC__) && (! defined(ZT_NO_TYPE_PUNNING))
  16. #define ZT_VAR_MAY_ALIAS __attribute__((__may_alias__))
  17. #else
  18. #define ZT_VAR_MAY_ALIAS
  19. #endif
  20. namespace ZeroTier {
  21. /**
  22. * A variable length but statically allocated buffer
  23. *
  24. * Bounds-checking is done everywhere, since this is used in security
  25. * critical code. This supports construction and assignment from buffers
  26. * of differing capacities, provided the data actually in them fits.
  27. * It throws std::out_of_range on any boundary violation.
  28. *
  29. * The at(), append(), etc. methods encode integers larger than 8-bit in
  30. * big-endian (network) byte order.
  31. *
  32. * @tparam C Total capacity
  33. */
  34. template <unsigned int C> class Buffer {
  35. // I love me!
  36. template <unsigned int C2> friend class Buffer;
  37. public:
  38. // STL container idioms
  39. typedef unsigned char value_type;
  40. typedef unsigned char* pointer;
  41. typedef const char* const_pointer;
  42. typedef char& reference;
  43. typedef const char& const_reference;
  44. typedef char* iterator;
  45. typedef const char* const_iterator;
  46. typedef unsigned int size_type;
  47. typedef int difference_type;
  48. typedef std::reverse_iterator<iterator> reverse_iterator;
  49. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  50. inline iterator begin()
  51. {
  52. return _b;
  53. }
  54. inline iterator end()
  55. {
  56. return (_b + _l);
  57. }
  58. inline const_iterator begin() const
  59. {
  60. return _b;
  61. }
  62. inline const_iterator end() const
  63. {
  64. return (_b + _l);
  65. }
  66. inline reverse_iterator rbegin()
  67. {
  68. return reverse_iterator(begin());
  69. }
  70. inline reverse_iterator rend()
  71. {
  72. return reverse_iterator(end());
  73. }
  74. inline const_reverse_iterator rbegin() const
  75. {
  76. return const_reverse_iterator(begin());
  77. }
  78. inline const_reverse_iterator rend() const
  79. {
  80. return const_reverse_iterator(end());
  81. }
  82. Buffer() : _l(0)
  83. {
  84. }
  85. Buffer(unsigned int l)
  86. {
  87. if (l > C) {
  88. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  89. }
  90. _l = l;
  91. }
  92. template <unsigned int C2> Buffer(const Buffer<C2>& b)
  93. {
  94. *this = b;
  95. }
  96. Buffer(const void* b, unsigned int l)
  97. {
  98. copyFrom(b, l);
  99. }
  100. template <unsigned int C2> inline Buffer& operator=(const Buffer<C2>& b)
  101. {
  102. if (unlikely(b._l > C)) {
  103. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  104. }
  105. if (C2 == C) {
  106. memcpy(this, &b, sizeof(Buffer<C>));
  107. }
  108. else {
  109. memcpy(_b, b._b, _l = b._l);
  110. }
  111. return *this;
  112. }
  113. inline void copyFrom(const void* b, unsigned int l)
  114. {
  115. if (unlikely(l > C)) {
  116. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  117. }
  118. memcpy(_b, b, l);
  119. _l = l;
  120. }
  121. unsigned char operator[](const unsigned int i) const
  122. {
  123. if (unlikely(i >= _l)) {
  124. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  125. }
  126. return (unsigned char)_b[i];
  127. }
  128. unsigned char& operator[](const unsigned int i)
  129. {
  130. if (unlikely(i >= _l)) {
  131. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  132. }
  133. return ((unsigned char*)_b)[i];
  134. }
  135. /**
  136. * Get a raw pointer to a field with bounds checking
  137. *
  138. * This isn't perfectly safe in that the caller could still overflow
  139. * the pointer, but its use provides both a sanity check and
  140. * documentation / reminder to the calling code to treat the returned
  141. * pointer as being of size [l].
  142. *
  143. * @param i Index of field in buffer
  144. * @param l Length of field in bytes
  145. * @return Pointer to field data
  146. * @throws std::out_of_range Field extends beyond data size
  147. */
  148. unsigned char* field(unsigned int i, unsigned int l)
  149. {
  150. if (unlikely((i + l) > _l)) {
  151. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  152. }
  153. return (unsigned char*)(_b + i);
  154. }
  155. const unsigned char* field(unsigned int i, unsigned int l) const
  156. {
  157. if (unlikely((i + l) > _l)) {
  158. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  159. }
  160. return (const unsigned char*)(_b + i);
  161. }
  162. /**
  163. * Place a primitive integer value at a given position
  164. *
  165. * @param i Index to place value
  166. * @param v Value
  167. * @tparam T Integer type (e.g. uint16_t, int64_t)
  168. */
  169. template <typename T> inline void setAt(unsigned int i, const T v)
  170. {
  171. if (unlikely((i + sizeof(T)) > _l)) {
  172. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  173. }
  174. #ifdef ZT_NO_TYPE_PUNNING
  175. uint8_t* p = reinterpret_cast<uint8_t*>(_b + i);
  176. for (unsigned int x = 1; x <= sizeof(T); ++x) {
  177. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  178. }
  179. #else
  180. T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + i);
  181. *p = Utils::hton(v);
  182. #endif
  183. }
  184. /**
  185. * Get a primitive integer value at a given position
  186. *
  187. * @param i Index to get integer
  188. * @tparam T Integer type (e.g. uint16_t, int64_t)
  189. * @return Integer value
  190. */
  191. template <typename T> inline T at(unsigned int i) const
  192. {
  193. if (unlikely((i + sizeof(T)) > _l)) {
  194. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  195. }
  196. #ifdef ZT_NO_TYPE_PUNNING
  197. T v = 0;
  198. const uint8_t* p = reinterpret_cast<const uint8_t*>(_b + i);
  199. for (unsigned int x = 0; x < sizeof(T); ++x) {
  200. v <<= 8;
  201. v |= (T) * (p++);
  202. }
  203. return v;
  204. #else
  205. const T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<const T*>(_b + i);
  206. return Utils::ntoh(*p);
  207. #endif
  208. }
  209. /**
  210. * Append an integer type to this buffer
  211. *
  212. * @param v Value to append
  213. * @tparam T Integer type (e.g. uint16_t, int64_t)
  214. * @throws std::out_of_range Attempt to append beyond capacity
  215. */
  216. template <typename T> inline void append(const T v)
  217. {
  218. if (unlikely((_l + sizeof(T)) > C)) {
  219. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  220. }
  221. #ifdef ZT_NO_TYPE_PUNNING
  222. uint8_t* p = reinterpret_cast<uint8_t*>(_b + _l);
  223. for (unsigned int x = 1; x <= sizeof(T); ++x) {
  224. *(p++) = (uint8_t)(v >> (8 * (sizeof(T) - x)));
  225. }
  226. #else
  227. T* const ZT_VAR_MAY_ALIAS p = reinterpret_cast<T*>(_b + _l);
  228. *p = Utils::hton(v);
  229. #endif
  230. _l += sizeof(T);
  231. }
  232. /**
  233. * Append a run of bytes
  234. *
  235. * @param c Character value to append
  236. * @param n Number of times to append
  237. * @throws std::out_of_range Attempt to append beyond capacity
  238. */
  239. inline void append(unsigned char c, unsigned int n)
  240. {
  241. if (unlikely((_l + n) > C)) {
  242. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  243. }
  244. for (unsigned int i = 0; i < n; ++i) {
  245. _b[_l++] = (char)c;
  246. }
  247. }
  248. /**
  249. * Append secure random bytes
  250. *
  251. * @param n Number of random bytes to append
  252. */
  253. inline void appendRandom(unsigned int n)
  254. {
  255. if (unlikely((_l + n) > C)) {
  256. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  257. }
  258. Utils::getSecureRandom(_b + _l, n);
  259. _l += n;
  260. }
  261. /**
  262. * Append a C-array of bytes
  263. *
  264. * @param b Data
  265. * @param l Length
  266. * @throws std::out_of_range Attempt to append beyond capacity
  267. */
  268. inline void append(const void* b, unsigned int l)
  269. {
  270. if (unlikely((_l + l) > C)) {
  271. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  272. }
  273. memcpy(_b + _l, b, l);
  274. _l += l;
  275. }
  276. /**
  277. * Append a C string including null termination byte
  278. *
  279. * @param s C string
  280. * @throws std::out_of_range Attempt to append beyond capacity
  281. */
  282. inline void appendCString(const char* s)
  283. {
  284. for (;;) {
  285. if (unlikely(_l >= C)) {
  286. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  287. }
  288. if (! (_b[_l++] = *(s++))) {
  289. break;
  290. }
  291. }
  292. }
  293. /**
  294. * Append a buffer
  295. *
  296. * @param b Buffer to append
  297. * @tparam C2 Capacity of second buffer (typically inferred)
  298. * @throws std::out_of_range Attempt to append beyond capacity
  299. */
  300. template <unsigned int C2> inline void append(const Buffer<C2>& b)
  301. {
  302. append(b._b, b._l);
  303. }
  304. /**
  305. * Increment size and return pointer to field of specified size
  306. *
  307. * Nothing is actually written to the memory. This is a shortcut
  308. * for addSize() followed by field() to reference the previous
  309. * position and the new size.
  310. *
  311. * @param l Length of field to append
  312. * @return Pointer to beginning of appended field of length 'l'
  313. */
  314. inline char* appendField(unsigned int l)
  315. {
  316. if (unlikely((_l + l) > C)) {
  317. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  318. }
  319. char* r = _b + _l;
  320. _l += l;
  321. return r;
  322. }
  323. /**
  324. * Increment size by a given number of bytes
  325. *
  326. * The contents of new space are undefined.
  327. *
  328. * @param i Bytes to increment
  329. * @throws std::out_of_range Capacity exceeded
  330. */
  331. inline void addSize(unsigned int i)
  332. {
  333. if (unlikely((i + _l) > C)) {
  334. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  335. }
  336. _l += i;
  337. }
  338. /**
  339. * Set size of data in buffer
  340. *
  341. * The contents of new space are undefined.
  342. *
  343. * @param i New size
  344. * @throws std::out_of_range Size larger than capacity
  345. */
  346. inline void setSize(const unsigned int i)
  347. {
  348. if (unlikely(i > C)) {
  349. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  350. }
  351. _l = i;
  352. }
  353. /**
  354. * Move everything after 'at' to the buffer's front and truncate
  355. *
  356. * @param at Truncate before this position
  357. * @throws std::out_of_range Position is beyond size of buffer
  358. */
  359. inline void behead(const unsigned int at)
  360. {
  361. if (! at) {
  362. return;
  363. }
  364. if (unlikely(at > _l)) {
  365. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  366. }
  367. ::memmove(_b, _b + at, _l -= at);
  368. }
  369. /**
  370. * Erase something from the middle of the buffer
  371. *
  372. * @param start Starting position
  373. * @param length Length of block to erase
  374. * @throws std::out_of_range Position plus length is beyond size of buffer
  375. */
  376. inline void erase(const unsigned int at, const unsigned int length)
  377. {
  378. const unsigned int endr = at + length;
  379. if (unlikely(endr > _l)) {
  380. throw ZT_EXCEPTION_OUT_OF_BOUNDS;
  381. }
  382. ::memmove(_b + at, _b + endr, _l - endr);
  383. _l -= length;
  384. }
  385. /**
  386. * Set buffer data length to zero
  387. */
  388. inline void clear()
  389. {
  390. _l = 0;
  391. }
  392. /**
  393. * Zero buffer up to size()
  394. */
  395. inline void zero()
  396. {
  397. memset(_b, 0, _l);
  398. }
  399. /**
  400. * Zero unused capacity area
  401. */
  402. inline void zeroUnused()
  403. {
  404. memset(_b + _l, 0, C - _l);
  405. }
  406. /**
  407. * Unconditionally and securely zero buffer's underlying memory
  408. */
  409. inline void burn()
  410. {
  411. Utils::burn(_b, sizeof(_b));
  412. }
  413. /**
  414. * @return Constant pointer to data in buffer
  415. */
  416. inline const void* data() const
  417. {
  418. return _b;
  419. }
  420. /**
  421. * @return Non-constant pointer to data in buffer
  422. */
  423. inline void* unsafeData()
  424. {
  425. return _b;
  426. }
  427. /**
  428. * @return Size of data in buffer
  429. */
  430. inline unsigned int size() const
  431. {
  432. return _l;
  433. }
  434. /**
  435. * @return Capacity of buffer
  436. */
  437. inline unsigned int capacity() const
  438. {
  439. return C;
  440. }
  441. template <unsigned int C2> inline bool operator==(const Buffer<C2>& b) const
  442. {
  443. return ((_l == b._l) && (! memcmp(_b, b._b, _l)));
  444. }
  445. template <unsigned int C2> inline bool operator!=(const Buffer<C2>& b) const
  446. {
  447. return ((_l != b._l) || (memcmp(_b, b._b, _l)));
  448. }
  449. template <unsigned int C2> inline bool operator<(const Buffer<C2>& b) const
  450. {
  451. return (memcmp(_b, b._b, std::min(_l, b._l)) < 0);
  452. }
  453. template <unsigned int C2> inline bool operator>(const Buffer<C2>& b) const
  454. {
  455. return (b < *this);
  456. }
  457. template <unsigned int C2> inline bool operator<=(const Buffer<C2>& b) const
  458. {
  459. return ! (b < *this);
  460. }
  461. template <unsigned int C2> inline bool operator>=(const Buffer<C2>& b) const
  462. {
  463. return ! (*this < b);
  464. }
  465. private:
  466. char ZT_VAR_MAY_ALIAS _b[C];
  467. unsigned int _l;
  468. };
  469. } // namespace ZeroTier
  470. #endif