MembershipCredential.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  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: 2025-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_CERTIFICATEOFMEMBERSHIP_HPP
  14. #define ZT_CERTIFICATEOFMEMBERSHIP_HPP
  15. #include <string>
  16. #include <stdexcept>
  17. #include <algorithm>
  18. #include "Constants.hpp"
  19. #include "Credential.hpp"
  20. #include "Address.hpp"
  21. #include "C25519.hpp"
  22. #include "Identity.hpp"
  23. #include "Utils.hpp"
  24. #include "FCV.hpp"
  25. // Maximum number of additional tuples beyond the standard always-present three.
  26. #define ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS 8
  27. // version + qualifier count + three required qualifiers + additional qualifiers +
  28. #define ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX (1 + 2 + (3 * 3 * 8) + (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS * 3 * 8) + 144 + 5 + 2 + 96)
  29. namespace ZeroTier {
  30. class RuntimeEnvironment;
  31. /**
  32. * Certificate of network membership
  33. *
  34. * This is the fundamental permission object issued by network controllers to members of networks
  35. * to admit them into networks.
  36. *
  37. * A certificate of membership (COM) consists of a series of tuples called qualifiers as well
  38. * as the full identity fingerprint of the node being admitted, the address of the controller
  39. * (for sanity checking), and a signature.
  40. *
  41. * A qualifier is a tuple of three 64-bit unsigned integers: an id, a value, and a delta.
  42. *
  43. * Certiciates are checked between peers by determining if they agree. If the absolute value
  44. * of the difference between any two qualifier values exceeds its delta, the certificates do
  45. * not agree. A delta if 1 for example means that the values of two peers may differ by no more
  46. * than one. A delta of 0 indicates values that must be the same. A delta of uint64_max is for
  47. * informational tuples that are not included in certificate checking, as this means they may
  48. * differ by any amount.
  49. *
  50. * All COMs contain three initial tuples: timestamp, network ID, and the address of the
  51. * issued-to node. The latter is informational. The network ID must equal exactly, though in
  52. * theory a controller could allow a delta there to e.g. allow cross-communication between all
  53. * of its networks. (This has never been done in practice.) The most important field is the
  54. * timestamp, whose delta defines a moving window within which certificates must be timestamped
  55. * by the network controller to agree. A certificate that is too old will fall out of this
  56. * window vs its peers and will no longer be considered valid.
  57. *
  58. * (Revocations are a method to rapidly revoke access that works alongside this slower but
  59. * more definitive method.)
  60. *
  61. * Certificate of membership wire format:
  62. *
  63. * This wire format comes in two versions: version 1 for ZeroTier 1.x, which will
  64. * eventually go away once 1.x is out of support, and version 2 for ZeroTier 2.x and later.
  65. *
  66. * Version 2:
  67. *
  68. * <[1] wire format type byte: 1 or 2>
  69. * <[2] 16-bit number of qualifier tuples>
  70. * <[...] qualifier tuples>
  71. * <[48] fingerprint hash of identity of peer to whom COM was issued>
  72. * <[5] address of network controller>
  73. * <[2] 16-bit size of signature>
  74. * <[...] signature>
  75. *
  76. * Version 1 is identical except the fingerprint hash is omitted and is instead loaded
  77. * into a series of six informational tuples. The signature size is also omitted and a
  78. * 96-byte signature field is assumed.
  79. *
  80. * Qualifier tuples must appear in numeric order of ID, and the first three tuples
  81. * must have IDs 0, 1, and 2 being the timestamp, network ID, and issued-to address
  82. * respectively. In version 1 COMs the IDs 3-8 are used to pack in the full identity
  83. * fingerprint, so these are reserved as well. Optional additional tuples (not currently
  84. * used) must use ID 65536 or higher.
  85. *
  86. * Signatures are computed over tuples only for backward compatibility with v1, and we
  87. * don't plan to change this. Tuples are emitted into a buffer in ascending numeric
  88. * order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is
  89. * then signed.
  90. */
  91. class MembershipCredential : public Credential
  92. {
  93. friend class Credential;
  94. public:
  95. static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_COM; }
  96. /**
  97. * Create an empty certificate of membership
  98. */
  99. ZT_INLINE MembershipCredential() noexcept { memoryZero(this); }
  100. /**
  101. * Create from required fields common to all networks
  102. *
  103. * @param timestamp Timestamp of certificate
  104. * @param timestampMaxDelta Maximum variation between timestamps on this net
  105. * @param nwid Network ID
  106. * @param issuedTo Certificate recipient
  107. */
  108. MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity &issuedTo) noexcept;
  109. /**
  110. * @return True if there's something here
  111. */
  112. ZT_INLINE operator bool() const noexcept { return (m_networkId != 0); }
  113. /**
  114. * @return Credential ID, always 0 for COMs
  115. */
  116. ZT_INLINE uint32_t id() const noexcept { return 0; }
  117. /**
  118. * @return Timestamp for this cert and maximum delta for timestamp
  119. */
  120. ZT_INLINE int64_t timestamp() const noexcept { return m_timestamp; }
  121. /**
  122. * @return Maximum allowed difference between timestamps
  123. */
  124. ZT_INLINE int64_t timestampMaxDelta() const noexcept { return m_timestampMaxDelta; }
  125. /**
  126. * @return Fingerprint of identity to which this cert was issued
  127. */
  128. ZT_INLINE const Fingerprint &issuedTo() const noexcept { return m_issuedTo; }
  129. /**
  130. * @return Network ID for which this cert was issued
  131. */
  132. ZT_INLINE uint64_t networkId() const noexcept { return m_networkId; }
  133. /**
  134. * Compare two certificates for parameter agreement
  135. *
  136. * This compares this certificate with the other and returns true if all
  137. * parameters in this cert are present in the other and if they agree to
  138. * within this cert's max delta value for each given parameter.
  139. *
  140. * Tuples present in other but not in this cert are ignored, but any
  141. * tuples present in this cert but not in other result in 'false'.
  142. *
  143. * @param other Cert to compare with
  144. * @return True if certs agree and 'other' may be communicated with
  145. */
  146. bool agreesWith(const MembershipCredential &other) const noexcept;
  147. /**
  148. * Sign this certificate
  149. *
  150. * @param with Identity to sign with, must include private key
  151. * @return True if signature was successful
  152. */
  153. bool sign(const Identity &with) noexcept;
  154. /**
  155. * Verify this COM and its signature
  156. *
  157. * @param RR Runtime environment for looking up peers
  158. * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
  159. */
  160. ZT_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return s_verify(RR, tPtr, *this); }
  161. // NOTE: right now we use v1 serialization format which works with both ZeroTier 1.x and 2.x. V2 format
  162. // will be switched on once 1.x is pretty much dead and out of support.
  163. static constexpr int marshalSizeMax() noexcept { return ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX; }
  164. int marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], bool v2 = false) const noexcept;
  165. int unmarshal(const uint8_t *data,int len) noexcept;
  166. private:
  167. unsigned int m_fillSigningBuf(uint64_t *buf) const noexcept;
  168. struct p_Qualifier
  169. {
  170. ZT_INLINE p_Qualifier() noexcept : id(0), value(0), delta(0) {}
  171. ZT_INLINE p_Qualifier(const uint64_t id_, const uint64_t value_, const uint64_t delta_) noexcept : id(id_), value(value_), delta(delta_) {}
  172. uint64_t id;
  173. uint64_t value;
  174. uint64_t delta;
  175. ZT_INLINE bool operator<(const p_Qualifier &q) const noexcept { return (id < q.id); } // sort order
  176. };
  177. FCV<p_Qualifier,ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS> m_additionalQualifiers;
  178. int64_t m_timestamp;
  179. int64_t m_timestampMaxDelta;
  180. uint64_t m_networkId;
  181. Fingerprint m_issuedTo;
  182. Address m_signedBy;
  183. unsigned int m_signatureLength;
  184. uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE];
  185. };
  186. } // namespace ZeroTier
  187. #endif