|
|
|
|
@ -41,50 +41,77 @@
|
|
|
|
|
|
|
|
|
|
namespace ZeroTier { |
|
|
|
|
|
|
|
|
|
void Network::Certificate::_shaForSignature(unsigned char *dig) const |
|
|
|
|
void Network::CertificateOfMembership::addParameter(uint64_t id,uint64_t value,uint64_t maxDelta) |
|
|
|
|
{ |
|
|
|
|
SHA256_CTX sha; |
|
|
|
|
SHA256_Init(&sha); |
|
|
|
|
unsigned char zero = 0; |
|
|
|
|
for(const_iterator i(begin());i!=end();++i) { |
|
|
|
|
SHA256_Update(&sha,&zero,1); |
|
|
|
|
SHA256_Update(&sha,(const unsigned char *)i->first.data(),i->first.length()); |
|
|
|
|
SHA256_Update(&sha,&zero,1); |
|
|
|
|
SHA256_Update(&sha,(const unsigned char *)i->second.data(),i->second.length()); |
|
|
|
|
SHA256_Update(&sha,&zero,1); |
|
|
|
|
_params.push_back(_Parameter(id,value,maxDelta)); |
|
|
|
|
std::sort(_params.begin(),_params.end(),_SortByIdComparison()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
std::string Network::CertificateOfMembership::toString() const |
|
|
|
|
{ |
|
|
|
|
uint64_t tmp[3000]; |
|
|
|
|
unsigned long n = 0; |
|
|
|
|
for(std::vector<_Parameter>::const_iterator p(_params.begin());p!=_params.end();++p) { |
|
|
|
|
tmp[n++] = Utils::hton(p->id); |
|
|
|
|
tmp[n++] = Utils::hton(p->value); |
|
|
|
|
tmp[n++] = Utils::hton(p->maxDelta); |
|
|
|
|
if (n >= 3000) |
|
|
|
|
break; // sanity check -- certificates will never even approach this size
|
|
|
|
|
} |
|
|
|
|
SHA256_Final(dig,&sha); |
|
|
|
|
return Utils::hex(tmp,sizeof(uint64_t) * n); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const std::string _DELTA_PREFIX("~"); |
|
|
|
|
bool Network::Certificate::qualifyMembership(const Network::Certificate &mc) const |
|
|
|
|
void Network::CertificateOfMembership::fromString(const char *s) |
|
|
|
|
{ |
|
|
|
|
// Note: optimization probably needed here, probably via some kind of
|
|
|
|
|
// memoization / dynamic programming. But make it work first, then make
|
|
|
|
|
// it fast.
|
|
|
|
|
|
|
|
|
|
for(const_iterator myField(begin());myField!=end();++myField) { |
|
|
|
|
if (!((myField->first.length() > 1)&&(myField->first[0] == '~'))) { // ~fields are max delta range specs
|
|
|
|
|
// If they lack the same field, comparison fails.
|
|
|
|
|
const_iterator theirField(mc.find(myField->first)); |
|
|
|
|
if (theirField == mc.end()) |
|
|
|
|
std::string tmp(Utils::unhex(s)); |
|
|
|
|
_params.clear(); |
|
|
|
|
const char *ptr = tmp.data(); |
|
|
|
|
unsigned long remaining = tmp.length(); |
|
|
|
|
while (remaining >= 24) { |
|
|
|
|
_Parameter p; |
|
|
|
|
p.id = Utils::ntoh(*((const uint64_t *)(ptr))); |
|
|
|
|
p.value = Utils::ntoh(*((const uint64_t *)(ptr + 8))); |
|
|
|
|
p.maxDelta = Utils::ntoh(*((const uint64_t *)(ptr + 16))); |
|
|
|
|
_params.push_back(p); |
|
|
|
|
ptr += 24; |
|
|
|
|
remaining -= 24; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool Network::CertificateOfMembership::compare(const CertificateOfMembership &other) const |
|
|
|
|
throw() |
|
|
|
|
{ |
|
|
|
|
unsigned long myidx = 0; |
|
|
|
|
unsigned long otheridx = 0; |
|
|
|
|
|
|
|
|
|
while (myidx < _params.size()) { |
|
|
|
|
// Fail if we're at the end of other, since this means the field is
|
|
|
|
|
// missing.
|
|
|
|
|
if (otheridx >= other._params.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._params[otheridx].id != _params[myidx].id) { |
|
|
|
|
++otheridx; |
|
|
|
|
if (otheridx >= other._params.size()) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const_iterator deltaField(find(_DELTA_PREFIX + myField->first)); |
|
|
|
|
if (deltaField == end()) { |
|
|
|
|
// If there is no delta, compare on simple equality
|
|
|
|
|
if (myField->second != theirField->second) |
|
|
|
|
return false; |
|
|
|
|
} else { |
|
|
|
|
// Otherwise compare the absolute value of the difference between
|
|
|
|
|
// the two values against the max delta.
|
|
|
|
|
int64_t my = Utils::hexStrTo64(myField->second.c_str()); |
|
|
|
|
int64_t their = Utils::hexStrTo64(theirField->second.c_str()); |
|
|
|
|
int64_t delta = Utils::hexStrTo64(deltaField->second.c_str()); |
|
|
|
|
if (llabs((long long)(my - their)) > delta) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
// Compare to determine if the absolute value of the difference
|
|
|
|
|
// between these two parameters is within our maxDelta.
|
|
|
|
|
uint64_t a = _params[myidx].value; |
|
|
|
|
uint64_t b = other._params[myidx].value; |
|
|
|
|
if (a >= b) { |
|
|
|
|
if ((a - b) > _params[myidx].maxDelta) |
|
|
|
|
return false; |
|
|
|
|
} else { |
|
|
|
|
if ((b - a) > _params[myidx].maxDelta) |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
++myidx; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
|