Tag.hpp 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c)2013-2020 ZeroTier, Inc.
  3. *
  4. * Use of this software is governed by the Business Source License included
  5. * in the LICENSE.TXT file in the project's root directory.
  6. *
  7. * Change Date: 2024-01-01
  8. *
  9. * On the date above, in accordance with the Business Source License, use
  10. * of this software will be governed by version 2.0 of the Apache License.
  11. */
  12. /****/
  13. #ifndef ZT_TAG_HPP
  14. #define ZT_TAG_HPP
  15. #include <cstdint>
  16. #include <cstdio>
  17. #include <cstdlib>
  18. #include <cstring>
  19. #include "Constants.hpp"
  20. #include "Credential.hpp"
  21. #include "C25519.hpp"
  22. #include "Address.hpp"
  23. #include "Identity.hpp"
  24. namespace ZeroTier {
  25. class RuntimeEnvironment;
  26. /**
  27. * A tag that can be associated with members and matched in rules
  28. *
  29. * Capabilities group rules, while tags group members subject to those
  30. * rules. Tag values can be matched in rules, and tags relevant to a
  31. * capability are presented along with it.
  32. *
  33. * E.g. a capability might be "can speak Samba/CIFS within your
  34. * department." This cap might have a rule to allow TCP/137 but
  35. * only if a given tag ID's value matches between two peers. The
  36. * capability is what members can do, while the tag is who they are.
  37. * Different departments might have tags with the same ID but different
  38. * values.
  39. *
  40. * Unlike capabilities tags are signed only by the issuer and are never
  41. * transferable.
  42. */
  43. class Tag : public Credential
  44. {
  45. friend class Credential;
  46. public:
  47. static ZT_ALWAYS_INLINE ZT_CredentialType credentialType() { return ZT_CREDENTIAL_TYPE_TAG; }
  48. ZT_ALWAYS_INLINE Tag() :
  49. _id(0),
  50. _value(0),
  51. _networkId(0),
  52. _ts(0),
  53. _signatureLength(0)
  54. {
  55. }
  56. /**
  57. * @param nwid Network ID
  58. * @param ts Timestamp
  59. * @param issuedTo Address to which this tag was issued
  60. * @param id Tag ID
  61. * @param value Tag value
  62. */
  63. ZT_ALWAYS_INLINE Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
  64. _id(id),
  65. _value(value),
  66. _networkId(nwid),
  67. _ts(ts),
  68. _issuedTo(issuedTo),
  69. _signedBy(),
  70. _signatureLength(0)
  71. {
  72. }
  73. ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
  74. ZT_ALWAYS_INLINE const uint32_t &value() const { return _value; }
  75. ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
  76. ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
  77. ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
  78. ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
  79. ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
  80. ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
  81. /**
  82. * Sign this tag
  83. *
  84. * @param signer Signing identity, must have private key
  85. * @return True if signature was successful
  86. */
  87. inline bool sign(const Identity &signer)
  88. {
  89. if (signer.hasPrivate()) {
  90. Buffer<sizeof(Tag) + 64> tmp;
  91. _signedBy = signer.address();
  92. this->serialize(tmp,true);
  93. _signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
  94. return true;
  95. }
  96. return false;
  97. }
  98. /**
  99. * Check this tag's signature
  100. *
  101. * @param RR Runtime environment to allow identity lookup for signedBy
  102. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  103. */
  104. ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
  105. template<unsigned int C>
  106. inline void serialize(Buffer<C> &b,const bool forSign = false) const
  107. {
  108. if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
  109. b.append(_networkId);
  110. b.append(_ts);
  111. b.append(_id);
  112. b.append(_value);
  113. _issuedTo.appendTo(b);
  114. _signedBy.appendTo(b);
  115. if (!forSign) {
  116. b.append((uint8_t)1);
  117. b.append((uint16_t)_signatureLength);
  118. b.append(_signature,_signatureLength);
  119. }
  120. b.append((uint16_t)0); // length of additional fields, currently 0
  121. if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
  122. }
  123. template<unsigned int C>
  124. inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
  125. {
  126. unsigned int p = startAt;
  127. *this = Tag();
  128. _networkId = b.template at<uint64_t>(p); p += 8;
  129. _ts = b.template at<uint64_t>(p); p += 8;
  130. _id = b.template at<uint32_t>(p); p += 4;
  131. _value = b.template at<uint32_t>(p); p += 4;
  132. _issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
  133. _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
  134. if (b[p++] == 1) {
  135. _signatureLength = b.template at<uint16_t>(p);
  136. if (_signatureLength > sizeof(_signature))
  137. throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
  138. p += 2;
  139. memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
  140. } else {
  141. p += 2 + b.template at<uint16_t>(p);
  142. }
  143. p += 2 + b.template at<uint16_t>(p);
  144. if (p > b.size())
  145. throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
  146. return (p - startAt);
  147. }
  148. // Provides natural sort order by ID
  149. ZT_ALWAYS_INLINE bool operator<(const Tag &t) const { return (_id < t._id); }
  150. ZT_ALWAYS_INLINE bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
  151. ZT_ALWAYS_INLINE bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
  152. // For searching sorted arrays or lists of Tags by ID
  153. struct IdComparePredicate
  154. {
  155. ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
  156. ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
  157. ZT_ALWAYS_INLINE bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
  158. ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
  159. ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
  160. ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
  161. ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
  162. ZT_ALWAYS_INLINE bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
  163. ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
  164. };
  165. private:
  166. uint32_t _id;
  167. uint32_t _value;
  168. uint64_t _networkId;
  169. int64_t _ts;
  170. Address _issuedTo;
  171. Address _signedBy;
  172. unsigned int _signatureLength;
  173. uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
  174. };
  175. } // namespace ZeroTier
  176. #endif