mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 20:43:44 +02:00
Remove capability chain of custody stuff which was never used and was really overly complex and a potential source of security problems.
This commit is contained in:
parent
87da45b3f5
commit
0d05e4bcae
7 changed files with 60 additions and 142 deletions
|
@ -189,11 +189,6 @@ extern "C" {
|
|||
*/
|
||||
#define ZT_MAX_CERTIFICATES_OF_OWNERSHIP 4
|
||||
|
||||
/**
|
||||
* Global maximum length for capability chain of custody (including initial issue)
|
||||
*/
|
||||
#define ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH 7
|
||||
|
||||
/* ----------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,7 @@ class Address : public TriviallyCopyable
|
|||
{
|
||||
public:
|
||||
ZT_INLINE Address() noexcept : _a(0) {}
|
||||
ZT_INLINE Address(const uint64_t a) noexcept : _a(a) {}
|
||||
explicit ZT_INLINE Address(const uint64_t a) noexcept : _a(a) {}
|
||||
explicit ZT_INLINE Address(const uint8_t b[5]) noexcept : _a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]) {}
|
||||
|
||||
ZT_INLINE Address &operator=(const Address &a) noexcept { _a = a._a; return *this; }
|
||||
|
|
|
@ -234,14 +234,6 @@ public:
|
|||
Utils::zero<ZT_BUF_MEM_SIZE>(unsafeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zero security critical data using Utils::burn() to ensure it's never optimized out.
|
||||
*/
|
||||
ZT_INLINE void burn() noexcept
|
||||
{
|
||||
Utils::burn(unsafeData,ZT_BUF_MEM_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte
|
||||
*
|
||||
|
|
|
@ -101,7 +101,7 @@ public:
|
|||
* @param siglen Length of signature in bytes
|
||||
* @return True if signature is valid and the message is authentic and unmodified
|
||||
*/
|
||||
static bool verify(const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,const void *signature,const unsigned int siglen);
|
||||
static bool verify(const uint8_t their[ZT_C25519_PUBLIC_KEY_LEN],const void *msg,unsigned int len,const void *signature,unsigned int siglen);
|
||||
|
||||
private:
|
||||
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
|
||||
|
|
|
@ -21,54 +21,52 @@ namespace ZeroTier {
|
|||
bool Capability::sign(const Identity &from,const Address &to) noexcept
|
||||
{
|
||||
uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16];
|
||||
try {
|
||||
for(unsigned int i=0;((i<_maxCustodyChainLength)&&(i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH));++i) {
|
||||
if (!(_custody[i].to)) {
|
||||
_custody[i].to = to;
|
||||
_custody[i].from = from.address();
|
||||
_custody[i].signatureLength = from.sign(buf,(unsigned int)marshal(buf,true),_custody[i].signature,sizeof(_custody[i].signature));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return false;
|
||||
_issuedTo = to;
|
||||
_signedBy = from.address();
|
||||
_signatureLength = from.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature));
|
||||
return _signatureLength > 0;
|
||||
}
|
||||
|
||||
int Capability::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],const bool forSign) const noexcept
|
||||
{
|
||||
int p = 0;
|
||||
|
||||
if (forSign) {
|
||||
for(int k=0;k<8;++k)
|
||||
data[p++] = 0x7f;
|
||||
}
|
||||
|
||||
Utils::storeBigEndian<uint64_t>(data + p,_nwid); p += 8;
|
||||
Utils::storeBigEndian<uint64_t>(data + p,(uint64_t)_ts); p += 8;
|
||||
Utils::storeBigEndian<uint32_t>(data + p,_id); p += 4;
|
||||
|
||||
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_ruleCount); p += 2;
|
||||
p += Capability::marshalVirtualNetworkRules(data + 22,_rules,_ruleCount);
|
||||
data[p++] = (uint8_t)_maxCustodyChainLength;
|
||||
p += Capability::marshalVirtualNetworkRules(data + p,_rules,_ruleCount);
|
||||
|
||||
// LEGACY: older versions supported multiple records with this being a maximum custody
|
||||
// chain length. This is deprecated so set the max chain length to one.
|
||||
data[p++] = (uint8_t)1;
|
||||
|
||||
if (!forSign) {
|
||||
for(unsigned int i=0;;++i) {
|
||||
if ((i < _maxCustodyChainLength)&&(i < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH)&&(_custody[i].to)) {
|
||||
_custody[i].to.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
|
||||
_custody[i].from.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
|
||||
data[p++] = 1;
|
||||
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_custody[i].signatureLength); p += 2;
|
||||
for(unsigned int k=0;k<_custody[i].signatureLength;++k)
|
||||
data[p++] = _custody[i].signature[k];
|
||||
} else {
|
||||
for(int k=0;k<ZT_ADDRESS_LENGTH;++k)
|
||||
data[p++] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
|
||||
_signedBy.copyTo(data + 0); p += ZT_ADDRESS_LENGTH;
|
||||
data[p++] = 1; // LEGACY: old versions require a reserved byte here
|
||||
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
|
||||
Utils::copy(data + p,_signature,_signatureLength); p += (int)_signatureLength;
|
||||
|
||||
// LEGACY: older versions supported more than one record terminated by a zero address.
|
||||
for(int k=0;k<ZT_ADDRESS_LENGTH;++k)
|
||||
data[p++] = 0;
|
||||
}
|
||||
|
||||
data[p++] = 0;
|
||||
data[p++] = 0; // uint16_t size of additional fields, currently 0
|
||||
|
||||
if (forSign) {
|
||||
for(int k=0;k<8;++k)
|
||||
data[p++] = 0x7f;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -81,7 +79,7 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
|
|||
_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
|
||||
_id = Utils::loadBigEndian<uint32_t>(data + 16);
|
||||
|
||||
const unsigned int rc = Utils::loadBigEndian<uint16_t>(data + 20);;
|
||||
const unsigned int rc = Utils::loadBigEndian<uint16_t>(data + 20);
|
||||
if (rc > ZT_MAX_CAPABILITY_RULES)
|
||||
return -1;
|
||||
const int rulesLen = unmarshalVirtualNetworkRules(data + 22,len - 22,_rules,_ruleCount,rc);
|
||||
|
@ -91,31 +89,37 @@ int Capability::unmarshal(const uint8_t *data,int len) noexcept
|
|||
|
||||
if (p >= len)
|
||||
return -1;
|
||||
_maxCustodyChainLength = data[p++];
|
||||
++p; // LEGACY: skip old max record count
|
||||
|
||||
// LEGACY: since it was once supported to have multiple records, scan them all. Since
|
||||
// this feature was never used, just set the signature and issued to and other related
|
||||
// fields each time and we should only ever see one. If there's more than one and the
|
||||
// last is not the controller, this credential will just fail validity check.
|
||||
for(unsigned int i=0;;++i) {
|
||||
if ((p + ZT_ADDRESS_LENGTH) > len)
|
||||
return -1;
|
||||
const Address to(data + p); p += ZT_ADDRESS_LENGTH;
|
||||
if (!to) break;
|
||||
if ((i >= _maxCustodyChainLength)||(i >= ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
return -1;
|
||||
_custody[i].to = to;
|
||||
|
||||
if (!to)
|
||||
break;
|
||||
|
||||
_issuedTo = to;
|
||||
if ((p + ZT_ADDRESS_LENGTH) > len)
|
||||
return -1;
|
||||
_custody[i].from.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1;
|
||||
_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1; // LEGACY: +1 to skip reserved field
|
||||
|
||||
if ((p + 2) > len)
|
||||
return -1;
|
||||
const unsigned int sl = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
|
||||
_custody[i].signatureLength = sl;
|
||||
if ((sl > sizeof(_custody[i].signature))||((p + (int)sl) > len))
|
||||
_signatureLength = Utils::loadBigEndian<uint16_t>(data + p); p += 2;
|
||||
if ((_signatureLength > sizeof(_signature))||((p + (int)_signatureLength) > len))
|
||||
return -1;
|
||||
Utils::copy(_custody[i].signature,data + p,sl); p += (int)sl;
|
||||
Utils::copy(_signature,data + p,_signatureLength); p += (int)_signatureLength;
|
||||
}
|
||||
|
||||
if ((p + 2) > len)
|
||||
return -1;
|
||||
p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
|
||||
|
||||
if (p > len)
|
||||
return -1;
|
||||
|
||||
|
@ -173,8 +177,7 @@ int Capability::marshalVirtualNetworkRules(uint8_t *data,const ZT_VirtualNetwork
|
|||
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
|
||||
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
|
||||
data[p++] = 17;
|
||||
for(int k=0;k<16;++k)
|
||||
data[p++] = rules[i].v.ipv6.ip[k];
|
||||
Utils::copy<16>(data + p,rules[i].v.ipv6.ip); p += 16;
|
||||
data[p++] = rules[i].v.ipv6.mask;
|
||||
break;
|
||||
case ZT_NETWORK_RULE_MATCH_IP_TOS:
|
||||
|
@ -250,7 +253,7 @@ int Capability::unmarshalVirtualNetworkRules(const uint8_t *const data,const int
|
|||
const int fieldLen = (int)data[p++];
|
||||
if ((p + fieldLen) > len)
|
||||
return -1;
|
||||
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3f)) {
|
||||
switch((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3fU)) {
|
||||
default:
|
||||
break;
|
||||
case ZT_NETWORK_RULE_ACTION_TEE:
|
||||
|
|
|
@ -26,16 +26,14 @@
|
|||
#include "Identity.hpp"
|
||||
|
||||
#define ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX 21
|
||||
|
||||
#define ZT_CAPABILITY__CUSTODY_CHAIN_ITEM_MARSHAL_SIZE_MAX (5 + 5 + 2 + ZT_SIGNATURE_BUFFER_SIZE)
|
||||
#define ZT_CAPABILITY_MARSHAL_SIZE_MAX (8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 + (ZT_CAPABILITY__CUSTODY_CHAIN_ITEM_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
#define ZT_CAPABILITY_MARSHAL_SIZE_MAX (8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 + (5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE))
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class RuntimeEnvironment;
|
||||
|
||||
/**
|
||||
* A set of grouped and signed network flow rules
|
||||
* A set of grouped and signed network flow rules for a specific member.
|
||||
*
|
||||
* On the sending side the sender does the following for each packet:
|
||||
*
|
||||
|
@ -51,11 +49,6 @@ class RuntimeEnvironment;
|
|||
*
|
||||
* Note that this is after evaluation of network scope rules and only if
|
||||
* network scope rules do not deliver an explicit match.
|
||||
*
|
||||
* Capabilities support a chain of custody. This is currently unused but
|
||||
* in the future would allow the publication of capabilities that can be
|
||||
* handed off between nodes. Limited transferability of capabilities is
|
||||
* a feature of true capability based security.
|
||||
*/
|
||||
class Capability : public Credential
|
||||
{
|
||||
|
@ -74,12 +67,12 @@ public:
|
|||
* @param rules Network flow rules for this capability
|
||||
* @param ruleCount Number of flow rules
|
||||
*/
|
||||
ZT_INLINE Capability(const uint32_t id,const uint64_t nwid,const int64_t ts,const unsigned int mccl,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) noexcept :
|
||||
ZT_INLINE Capability(const uint32_t id,const uint64_t nwid,const int64_t ts,const ZT_VirtualNetworkRule *const rules,const unsigned int ruleCount) noexcept :
|
||||
_nwid(nwid),
|
||||
_ts(ts),
|
||||
_id(id),
|
||||
_maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1),
|
||||
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
|
||||
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES),
|
||||
_signatureLength(0)
|
||||
{
|
||||
if (_ruleCount > 0)
|
||||
Utils::copy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
|
||||
|
@ -95,34 +88,13 @@ public:
|
|||
*/
|
||||
ZT_INLINE unsigned int ruleCount() const noexcept { return _ruleCount; }
|
||||
|
||||
/**
|
||||
* @return ID and evaluation order of this capability in network
|
||||
*/
|
||||
ZT_INLINE uint32_t id() const noexcept { return _id; }
|
||||
|
||||
/**
|
||||
* @return Network ID for which this capability was issued
|
||||
*/
|
||||
ZT_INLINE uint64_t networkId() const noexcept { return _nwid; }
|
||||
|
||||
/**
|
||||
* @return Timestamp
|
||||
*/
|
||||
ZT_INLINE int64_t timestamp() const noexcept { return _ts; }
|
||||
|
||||
/**
|
||||
* @return Last 'to' address in chain of custody
|
||||
*/
|
||||
ZT_INLINE Address issuedTo() const noexcept
|
||||
{
|
||||
Address i2;
|
||||
for(int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
|
||||
if (!_custody[i].to)
|
||||
return i2;
|
||||
else i2 = _custody[i].to;
|
||||
}
|
||||
return i2;
|
||||
}
|
||||
ZT_INLINE const Address &issuedTo() const noexcept { return _issuedTo; }
|
||||
ZT_INLINE const Address &signer() const noexcept { return _signedBy; }
|
||||
ZT_INLINE const uint8_t *signature() const noexcept { return _signature; }
|
||||
ZT_INLINE unsigned int signatureLength() const noexcept { return _signatureLength; }
|
||||
|
||||
/**
|
||||
* Sign this capability and add signature to its chain of custody
|
||||
|
@ -182,18 +154,12 @@ private:
|
|||
uint64_t _nwid;
|
||||
int64_t _ts;
|
||||
uint32_t _id;
|
||||
|
||||
unsigned int _maxCustodyChainLength;
|
||||
|
||||
unsigned int _ruleCount;
|
||||
ZT_VirtualNetworkRule _rules[ZT_MAX_CAPABILITY_RULES];
|
||||
|
||||
struct {
|
||||
Address to;
|
||||
Address from;
|
||||
unsigned int signatureLength;
|
||||
uint8_t signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
} _custody[ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH];
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
unsigned int _signatureLength;
|
||||
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -68,6 +68,7 @@ static ZT_INLINE Credential::VerifyResult _credVerify(const RuntimeEnvironment *
|
|||
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Revocation &credential) const { return _credVerify(RR,tPtr,credential); }
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Tag &credential) const { return _credVerify(RR,tPtr,credential); }
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const Capability &credential) const { return _credVerify(RR,tPtr,credential); }
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfOwnership &credential) const { return _credVerify(RR,tPtr,credential); }
|
||||
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,void *tPtr,const CertificateOfMembership &credential) const
|
||||
|
@ -87,43 +88,4 @@ Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *const RR,
|
|||
return peer->identity().verify(buf,bufSize,credential._signature,credential._signatureLength) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE;
|
||||
}
|
||||
|
||||
Credential::VerifyResult Credential::_verify(const RuntimeEnvironment *RR,void *tPtr,const Capability &credential) const
|
||||
{
|
||||
uint8_t tmp[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16];
|
||||
try {
|
||||
// There must be at least one entry, and sanity check for bad chain max length
|
||||
if ((credential._maxCustodyChainLength < 1)||(credential._maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
|
||||
return Credential::VERIFY_BAD_SIGNATURE;
|
||||
|
||||
int l = credential.marshal(tmp,true);
|
||||
if (l <= 0)
|
||||
return Credential::VERIFY_BAD_SIGNATURE;
|
||||
|
||||
// Validate all entries in chain of custody
|
||||
for(unsigned int c=0;c<credential._maxCustodyChainLength;++c) {
|
||||
if (c == 0) {
|
||||
if ((!credential._custody[c].to)||(!credential._custody[c].from)||(credential._custody[c].from != Network::controllerFor(credential._nwid)))
|
||||
return Credential::VERIFY_BAD_SIGNATURE; // the first entry must be present and from the network's controller
|
||||
} else {
|
||||
if (!credential._custody[c].to)
|
||||
return Credential::VERIFY_OK; // all previous entries were valid, so we are valid
|
||||
else if ((!credential._custody[c].from)||(credential._custody[c].from != credential._custody[c-1].to))
|
||||
return Credential::VERIFY_BAD_SIGNATURE; // otherwise if we have another entry it must be from the previous holder in the chain
|
||||
}
|
||||
|
||||
const SharedPtr<Peer> peer(RR->topology->peer(tPtr,credential._custody[c].from));
|
||||
if (peer) {
|
||||
if (!peer->identity().verify(tmp,(unsigned int)l,credential._custody[c].signature,credential._custody[c].signatureLength))
|
||||
return Credential::VERIFY_BAD_SIGNATURE;
|
||||
} else {
|
||||
return Credential::VERIFY_NEED_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
// We reached max custody chain length and everything was valid
|
||||
return Credential::VERIFY_OK;
|
||||
} catch ( ... ) {}
|
||||
return Credential::VERIFY_BAD_SIGNATURE;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
Loading…
Add table
Reference in a new issue