CertificateOfMembership.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /*
  2. * ZeroTier One - Network Virtualization Everywhere
  3. * Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * --
  19. *
  20. * You can be released from the requirements of the license by purchasing
  21. * a commercial license. Buying such a license is mandatory as soon as you
  22. * develop commercial closed-source software that incorporates or links
  23. * directly against ZeroTier software without disclosing the source code
  24. * of your own application.
  25. */
  26. #include "CertificateOfMembership.hpp"
  27. #include "RuntimeEnvironment.hpp"
  28. #include "Topology.hpp"
  29. #include "Switch.hpp"
  30. #include "Network.hpp"
  31. #include "Node.hpp"
  32. namespace ZeroTier {
  33. void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
  34. {
  35. _signedBy.zero();
  36. for(unsigned int i=0;i<_qualifierCount;++i) {
  37. if (_qualifiers[i].id == id) {
  38. _qualifiers[i].value = value;
  39. _qualifiers[i].maxDelta = maxDelta;
  40. return;
  41. }
  42. }
  43. if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
  44. _qualifiers[_qualifierCount].id = id;
  45. _qualifiers[_qualifierCount].value = value;
  46. _qualifiers[_qualifierCount].maxDelta = maxDelta;
  47. ++_qualifierCount;
  48. std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
  49. }
  50. }
  51. #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
  52. std::string CertificateOfMembership::toString() const
  53. {
  54. char tmp[ZT_NETWORK_COM_MAX_QUALIFIERS * 32];
  55. std::string s;
  56. s.append("1:"); // COM_UINT64_ED25519
  57. uint64_t *const buf = new uint64_t[_qualifierCount * 3];
  58. try {
  59. unsigned int ptr = 0;
  60. for(unsigned int i=0;i<_qualifierCount;++i) {
  61. buf[ptr++] = Utils::hton(_qualifiers[i].id);
  62. buf[ptr++] = Utils::hton(_qualifiers[i].value);
  63. buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
  64. }
  65. s.append(Utils::hex(buf,ptr * sizeof(uint64_t),tmp));
  66. delete [] buf;
  67. } catch ( ... ) {
  68. delete [] buf;
  69. throw;
  70. }
  71. s.push_back(':');
  72. s.append(_signedBy.toString(tmp));
  73. if (_signedBy) {
  74. s.push_back(':');
  75. s.append(Utils::hex(_signature.data,ZT_C25519_SIGNATURE_LEN,tmp));
  76. }
  77. return s;
  78. }
  79. void CertificateOfMembership::fromString(const char *s)
  80. {
  81. _qualifierCount = 0;
  82. _signedBy.zero();
  83. memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
  84. if (!*s)
  85. return;
  86. unsigned int colonAt = 0;
  87. while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
  88. if (!((colonAt == 1)&&(s[0] == '1'))) // COM_UINT64_ED25519?
  89. return;
  90. s += colonAt + 1;
  91. colonAt = 0;
  92. while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
  93. if (colonAt) {
  94. const unsigned int buflen = colonAt / 2;
  95. char *const buf = new char[buflen];
  96. unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen);
  97. char *bufptr = buf;
  98. try {
  99. while (bufactual >= 24) {
  100. if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
  101. _qualifiers[_qualifierCount].id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
  102. _qualifiers[_qualifierCount].value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
  103. _qualifiers[_qualifierCount].maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
  104. ++_qualifierCount;
  105. } else {
  106. bufptr += 24;
  107. }
  108. bufactual -= 24;
  109. }
  110. } catch ( ... ) {}
  111. delete [] buf;
  112. }
  113. if (s[colonAt]) {
  114. s += colonAt + 1;
  115. colonAt = 0;
  116. while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
  117. if (colonAt) {
  118. char addrbuf[ZT_ADDRESS_LENGTH];
  119. if (Utils::unhex(s,colonAt,addrbuf,sizeof(addrbuf)) == ZT_ADDRESS_LENGTH)
  120. _signedBy.setTo(addrbuf,ZT_ADDRESS_LENGTH);
  121. if ((_signedBy)&&(s[colonAt])) {
  122. s += colonAt + 1;
  123. colonAt = 0;
  124. while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
  125. if (colonAt) {
  126. if (Utils::unhex(s,colonAt,_signature.data,ZT_C25519_SIGNATURE_LEN) != ZT_C25519_SIGNATURE_LEN)
  127. _signedBy.zero();
  128. } else {
  129. _signedBy.zero();
  130. }
  131. } else {
  132. _signedBy.zero();
  133. }
  134. }
  135. }
  136. std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
  137. }
  138. #endif // ZT_SUPPORT_OLD_STYLE_NETCONF
  139. bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const
  140. {
  141. unsigned int myidx = 0;
  142. unsigned int otheridx = 0;
  143. if ((_qualifierCount == 0)||(other._qualifierCount == 0))
  144. return false;
  145. while (myidx < _qualifierCount) {
  146. // Fail if we're at the end of other, since this means the field is
  147. // missing.
  148. if (otheridx >= other._qualifierCount)
  149. return false;
  150. // Seek to corresponding tuple in other, ignoring tuples that
  151. // we may not have. If we run off the end of other, the tuple is
  152. // missing. This works because tuples are sorted by ID.
  153. while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) {
  154. ++otheridx;
  155. if (otheridx >= other._qualifierCount)
  156. return false;
  157. }
  158. // Compare to determine if the absolute value of the difference
  159. // between these two parameters is within our maxDelta.
  160. const uint64_t a = _qualifiers[myidx].value;
  161. const uint64_t b = other._qualifiers[myidx].value;
  162. if (((a >= b) ? (a - b) : (b - a)) > _qualifiers[myidx].maxDelta)
  163. return false;
  164. ++myidx;
  165. }
  166. return true;
  167. }
  168. bool CertificateOfMembership::sign(const Identity &with)
  169. {
  170. uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
  171. unsigned int ptr = 0;
  172. for(unsigned int i=0;i<_qualifierCount;++i) {
  173. buf[ptr++] = Utils::hton(_qualifiers[i].id);
  174. buf[ptr++] = Utils::hton(_qualifiers[i].value);
  175. buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
  176. }
  177. try {
  178. _signature = with.sign(buf,ptr * sizeof(uint64_t));
  179. _signedBy = with.address();
  180. return true;
  181. } catch ( ... ) {
  182. _signedBy.zero();
  183. return false;
  184. }
  185. }
  186. int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) const
  187. {
  188. if ((!_signedBy)||(_signedBy != Network::controllerFor(networkId()))||(_qualifierCount > ZT_NETWORK_COM_MAX_QUALIFIERS))
  189. return -1;
  190. const Identity id(RR->topology->getIdentity(tPtr,_signedBy));
  191. if (!id) {
  192. RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy);
  193. return 1;
  194. }
  195. uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
  196. unsigned int ptr = 0;
  197. for(unsigned int i=0;i<_qualifierCount;++i) {
  198. buf[ptr++] = Utils::hton(_qualifiers[i].id);
  199. buf[ptr++] = Utils::hton(_qualifiers[i].value);
  200. buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
  201. }
  202. return (id.verify(buf,ptr * sizeof(uint64_t),_signature) ? 0 : -1);
  203. }
  204. } // namespace ZeroTier