diff options
| author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-07 15:29:03 -0400 |
|---|---|---|
| committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-07 15:29:03 -0400 |
| commit | b4ae1adfbffecc090357b4e9e5c04ec3b2d3280d (patch) | |
| tree | afbdd85656f7a80763b46738f3955245ec191851 /node/CertificateOfMembership.cpp | |
| parent | dcbc9c8ddd7cdb543e213e3402050724174df03a (diff) | |
| download | infinitytier-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.cpp | 220 |
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 |
