summaryrefslogtreecommitdiff
path: root/node/CertificateOfMembership.cpp
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-07 15:29:03 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-07 15:29:03 -0400
commitb4ae1adfbffecc090357b4e9e5c04ec3b2d3280d (patch)
treeafbdd85656f7a80763b46738f3955245ec191851 /node/CertificateOfMembership.cpp
parentdcbc9c8ddd7cdb543e213e3402050724174df03a (diff)
downloadinfinitytier-b4ae1adfbffecc090357b4e9e5c04ec3b2d3280d.tar.gz
infinitytier-b4ae1adfbffecc090357b4e9e5c04ec3b2d3280d.zip
Break out certificate of membership into its own class.
Diffstat (limited to 'node/CertificateOfMembership.cpp')
-rw-r--r--node/CertificateOfMembership.cpp220
1 files changed, 220 insertions, 0 deletions
diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp
new file mode 100644
index 00000000..0944851a
--- /dev/null
+++ b/node/CertificateOfMembership.cpp
@@ -0,0 +1,220 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013 ZeroTier Networks LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include <algorithm>
+
+#include "CertificateOfMembership.hpp"
+
+namespace ZeroTier {
+
+void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
+{
+ _signedBy.zero();
+
+ for(std::vector<_Qualifier>::iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
+ if (q->id == id) {
+ q->value = value;
+ q->maxDelta = maxDelta;
+ return;
+ }
+ }
+
+ _qualifiers.push_back(_Qualifier(id,value,maxDelta));
+ std::sort(_qualifiers.begin(),_qualifiers.end());
+}
+
+std::string CertificateOfMembership::toString() const
+{
+ std::string s;
+
+ uint64_t *buf = new uint64_t[_qualifiers.size() * 3];
+ try {
+ unsigned int ptr = 0;
+ for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
+ buf[ptr++] = Utils::hton(q->id);
+ buf[ptr++] = Utils::hton(q->value);
+ buf[ptr++] = Utils::hton(q->maxDelta);
+ }
+ s.append(Utils::hex(buf,ptr * sizeof(uint64_t)));
+ delete [] buf;
+ } catch ( ... ) {
+ delete [] buf;
+ throw;
+ }
+
+ s.push_back(':');
+
+ s.append(_signedBy.toString());
+
+ if (_signedBy) {
+ s.push_back(':');
+ s.append(Utils::hex(_signature.data,_signature.size()));
+ }
+
+ return s;
+}
+
+void CertificateOfMembership::fromString(const char *s)
+{
+ _qualifiers.clear();
+ _signedBy.zero();
+ memset(_signature.data,0,_signature.size());
+
+ unsigned int colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (colonAt) {
+ unsigned int buflen = colonAt / 2;
+ char *buf = new char[buflen];
+ unsigned int bufactual = Utils::unhex(s,colonAt,buf,buflen);
+ char *bufptr = buf;
+ try {
+ while (bufactual >= 24) {
+ _qualifiers.push_back(_Qualifier());
+ _qualifiers.back().id = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ _qualifiers.back().value = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ _qualifiers.back().maxDelta = Utils::ntoh(*((uint64_t *)bufptr)); bufptr += 8;
+ bufactual -= 24;
+ }
+ } catch ( ... ) {}
+ delete [] buf;
+ }
+
+ if (s[colonAt]) {
+ s += colonAt + 1;
+ colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (colonAt) {
+ char addrbuf[ZT_ADDRESS_LENGTH];
+ if (Utils::unhex(s,colonAt,addrbuf,sizeof(addrbuf)) == ZT_ADDRESS_LENGTH)
+ _signedBy.setTo(addrbuf,ZT_ADDRESS_LENGTH);
+
+ if ((_signedBy)&&(s[colonAt])) {
+ s += colonAt + 1;
+ colonAt = 0;
+ while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
+
+ if (colonAt) {
+ if (Utils::unhex(s,colonAt,_signature.data,_signature.size()) != _signature.size())
+ _signedBy.zero();
+ } else _signedBy.zero();
+ } else _signedBy.zero();
+ }
+ }
+
+ std::sort(_qualifiers.begin(),_qualifiers.end());
+ std::unique(_qualifiers.begin(),_qualifiers.end());
+}
+
+bool CertificateOfMembership::agreesWith(const CertificateOfMembership &other) const
+ throw()
+{
+ unsigned long myidx = 0;
+ unsigned long otheridx = 0;
+
+ while (myidx < _qualifiers.size()) {
+ // Fail if we're at the end of other, since this means the field is
+ // missing.
+ if (otheridx >= other._qualifiers.size())
+ return false;
+
+ // Seek to corresponding tuple in other, ignoring tuples that
+ // we may not have. If we run off the end of other, the tuple is
+ // missing. This works because tuples are sorted by ID.
+ while (other._qualifiers[otheridx].id != _qualifiers[myidx].id) {
+ ++otheridx;
+ if (otheridx >= other._qualifiers.size())
+ return false;
+ }
+
+ // Compare to determine if the absolute value of the difference
+ // between these two parameters is within our maxDelta.
+ uint64_t a = _qualifiers[myidx].value;
+ uint64_t b = other._qualifiers[myidx].value;
+ if (a >= b) {
+ if ((a - b) > _qualifiers[myidx].maxDelta)
+ return false;
+ } else {
+ if ((b - a) > _qualifiers[myidx].maxDelta)
+ return false;
+ }
+
+ ++myidx;
+ }
+
+ return true;
+}
+
+bool CertificateOfMembership::sign(const Identity &with)
+{
+ uint64_t *buf = new uint64_t[_qualifiers.size() * 3];
+ unsigned int ptr = 0;
+ for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
+ buf[ptr++] = Utils::hton(q->id);
+ buf[ptr++] = Utils::hton(q->value);
+ buf[ptr++] = Utils::hton(q->maxDelta);
+ }
+
+ try {
+ _signature = with.sign(buf,ptr * sizeof(uint64_t));
+ _signedBy = with.address();
+ delete [] buf;
+ return true;
+ } catch ( ... ) {
+ _signedBy.zero();
+ delete [] buf;
+ return false;
+ }
+}
+
+bool CertificateOfMembership::verify(const Identity &id) const
+{
+ if (!_signedBy)
+ return false;
+ if (id.address() != _signedBy)
+ return false;
+
+ uint64_t *buf = new uint64_t[_qualifiers.size() * 3];
+ unsigned int ptr = 0;
+ for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
+ buf[ptr++] = Utils::hton(q->id);
+ buf[ptr++] = Utils::hton(q->value);
+ buf[ptr++] = Utils::hton(q->maxDelta);
+ }
+
+ bool valid = false;
+ try {
+ valid = id.verify(buf,ptr * sizeof(uint64_t),_signature);
+ delete [] buf;
+ } catch ( ... ) {
+ delete [] buf;
+ }
+ return valid;
+}
+
+} // namespace ZeroTier