Dictionary.hpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /*
  2. * ZeroTier One - Global Peer to Peer Ethernet
  3. * Copyright (C) 2011-2014 ZeroTier Networks LLC
  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. * ZeroTier may be used and distributed under the terms of the GPLv3, which
  21. * are available at: http://www.gnu.org/licenses/gpl-3.0.html
  22. *
  23. * If you would like to embed ZeroTier into a commercial application or
  24. * redistribute it in a modified binary form, please contact ZeroTier Networks
  25. * LLC. Start here: http://www.zerotier.com/
  26. */
  27. #ifndef ZT_DICTIONARY_HPP
  28. #define ZT_DICTIONARY_HPP
  29. #include <stdint.h>
  30. #include <string>
  31. #include <map>
  32. #include <stdexcept>
  33. #include "Constants.hpp"
  34. // Three fields are added/updated by sign()
  35. #define ZT_DICTIONARY_SIGNATURE "~!ed25519"
  36. #define ZT_DICTIONARY_SIGNATURE_IDENTITY "~!sigid"
  37. #define ZT_DICTIONARY_SIGNATURE_TIMESTAMP "~!sigts"
  38. namespace ZeroTier {
  39. class Identity;
  40. /**
  41. * Simple key/value dictionary with string serialization
  42. *
  43. * The serialization format is a flat key=value with backslash escape.
  44. * It does not support comments or other syntactic complexities. It is
  45. * human-readable if the keys and values in the dictionary are also
  46. * human-readable. Otherwise it might contain unprintable characters.
  47. *
  48. * Keys beginning with "~!" are reserved for signature data fields.
  49. *
  50. * Note: the signature code depends on std::map<> being sorted, but no
  51. * other code does. So if the underlying data structure is ever swapped
  52. * out for an unsorted one, the signature code will have to be updated
  53. * to sort before composing the string to sign.
  54. */
  55. class Dictionary : public std::map<std::string,std::string>
  56. {
  57. public:
  58. Dictionary() {}
  59. /**
  60. * @param s String-serialized dictionary
  61. * @param maxlen Maximum length of buffer
  62. */
  63. Dictionary(const char *s,unsigned int maxlen) { fromString(s,maxlen); }
  64. /**
  65. * @param s String-serialized dictionary
  66. */
  67. Dictionary(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
  68. /**
  69. * Get a key, throwing an exception if it is not present
  70. *
  71. * @param key Key to look up
  72. * @return Reference to value
  73. * @throws std::invalid_argument Key not found
  74. */
  75. inline const std::string &get(const std::string &key) const
  76. throw(std::invalid_argument)
  77. {
  78. const_iterator e(find(key));
  79. if (e == end())
  80. throw std::invalid_argument(std::string("missing required field: ")+key);
  81. return e->second;
  82. }
  83. /**
  84. * Get a key, returning a default if not present
  85. *
  86. * @param key Key to look up
  87. * @param dfl Default if not present
  88. * @return Value or default
  89. */
  90. inline const std::string &get(const std::string &key,const std::string &dfl) const
  91. {
  92. const_iterator e(find(key));
  93. if (e == end())
  94. return dfl;
  95. return e->second;
  96. }
  97. /**
  98. * @param key Key to check
  99. * @return True if dictionary contains key
  100. */
  101. inline bool contains(const std::string &key) const { return (find(key) != end()); }
  102. /**
  103. * @return String-serialized dictionary
  104. */
  105. inline std::string toString() const
  106. {
  107. std::string s;
  108. for(const_iterator kv(begin());kv!=end();++kv) {
  109. _appendEsc(kv->first.data(),(unsigned int)kv->first.length(),s);
  110. s.push_back('=');
  111. _appendEsc(kv->second.data(),(unsigned int)kv->second.length(),s);
  112. s.append(ZT_EOL_S);
  113. }
  114. return s;
  115. }
  116. /**
  117. * Clear and initialize from a string
  118. *
  119. * @param s String-serialized dictionary
  120. * @param maxlen Maximum length of string buffer
  121. */
  122. void fromString(const char *s,unsigned int maxlen);
  123. inline void fromString(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
  124. /**
  125. * @return True if this dictionary is cryptographically signed
  126. */
  127. inline bool hasSignature() const { return (find(ZT_DICTIONARY_SIGNATURE) != end()); }
  128. /**
  129. * @return Signing identity in string-serialized format or empty string if none
  130. */
  131. inline std::string signingIdentity() const { return get(ZT_DICTIONARY_SIGNATURE_IDENTITY,std::string()); }
  132. /**
  133. * @return Signature timestamp in milliseconds since epoch or 0 if none
  134. */
  135. uint64_t signatureTimestamp() const;
  136. /**
  137. * Remove any signature from this dictionary
  138. */
  139. inline void removeSignature()
  140. {
  141. erase(ZT_DICTIONARY_SIGNATURE);
  142. erase(ZT_DICTIONARY_SIGNATURE_IDENTITY);
  143. erase(ZT_DICTIONARY_SIGNATURE_TIMESTAMP);
  144. }
  145. /**
  146. * Add or update signature fields with a signature of all other keys and values
  147. *
  148. * @param with Identity to sign with (must have secret key)
  149. * @return True on success
  150. */
  151. bool sign(const Identity &id);
  152. /**
  153. * Verify signature against an identity
  154. *
  155. * @param id Identity to verify against
  156. * @return True if signature verification OK
  157. */
  158. bool verify(const Identity &id) const;
  159. private:
  160. void _mkSigBuf(std::string &buf) const;
  161. static void _appendEsc(const char *data,unsigned int len,std::string &to);
  162. };
  163. } // namespace ZeroTier
  164. #endif